java學習第十二天之多執行緒死鎖和併發
阿新 • • 發佈:2019-01-26
package MoreThreadLearn;
/*
兩個儲戶到銀行存錢,每個人存了三次,一次100元
1、描述銀行
2、描述儲戶業務
分析多執行緒是否存在安全隱患?
1、執行緒任務中是否有共享的資料
2、是否多條操作共享資料的程式碼
*/
public class ThreadA {
public static void main(String[] args) {
// 建立任務物件
Customer customer=new Customer();
Thread t1=new Thread(customer);
Thread t2=new Thread(customer);
t1.start();
t2.start();
}
}
/*
同步函式:其實就是在函式上加上了 同步關鍵字 進行修飾
同步表現形式有兩種:1、同步程式碼塊 2、同步函式
同步函式使用的鎖是什麼呢?
函式需要被物件呼叫,那個物件不確定,但是函式一定要通過物件來呼叫,物件使用this
*/
/*
如果同步函式被static修飾呢?
static方法隨著類載入,這時不一定有該類的物件,但是一定有一個該類的位元組碼檔案物件
這個物件簡單的表示就是 類名.class Class
*/
/*
懶漢式
在多執行緒併發誓,會出現執行緒安全問題
加了同步就可以解決問題,無論是同步函式還是同步程式碼塊都行,
但是,效率降低了
解決效率低的問題
可以通過if對單例物件的雙重判斷的形式
*/
/*
同步函式,同步程式碼塊
同步程式碼塊使用任意的物件作為鎖
同步函式只能使用this作為鎖
如果說:一個類中只需要一個鎖,這是可以考慮同步函式,使用this,寫法簡單
但是,一個類中如果需要多個鎖,還有多個類中使用同一個鎖,這是隻能使用同步程式碼塊
*/
class Bank{
private int sum;
private Object obj = new Object();
/*public void add(int n) {
synchronized (obj) {//同步程式碼 ,防非同步
sum+=n;
try {
Thread.sleep(5);
} catch (Exception e) {}
System.out.println("sum="+sum);
}
}*/
//另一種寫法 同步程式碼 ,防非同步
public synchronized void add(int n) {
sum+=n;
try {
Thread.sleep(5);
} catch (Exception e) {}
System.out.println("sum="+sum);
}
}
class Customer implements Runnable{
private Bank bank=new Bank();
private static Customer c2=null;
public void run() {
for(int x=0;x<3;x++){
bank.add(100);
}
}
public static synchronized Customer getInstance() {
int sum=100;
if(c2==null){
synchronized (Customer.class) {
if(c2==null){
c2 =new Customer();
}
}
}
try {
Thread.sleep(5);
} catch (Exception e) {}
System.out.println("sum="+sum);
return c2;
}
}
package MoreThreadLearn;
import java.util.Set;
/*
多執行緒間的通訊,多個執行緒都在處理同一個資源,但是處理的任務卻不一樣
生產者,消費者
通過同步,解決了沒生產就消費的問題
但是出現了連續的生產沒有消費的情況,和需求生產一個,消費一個的情況不符
使用了等待喚醒機制
wait();//該方法可以讓執行緒處於凍結狀態,並將執行緒臨時儲存到執行緒池中國
notify();//喚醒指定執行緒池中的任意一個執行緒
notifyAll();//喚醒指定執行緒池中的所有執行緒
這些方法必須使用在同步中,因為它們又來操作同步鎖上的現成的狀態的
在使用這些方法時,必須標識它們所屬於的鎖,標識方式就是 鎖物件.wait(); 鎖物件.notify(); 鎖物件.notifyAll();
相同鎖的notify(),可以獲取相同鎖的wait();
*/
/*
多生產多消費
問題1:
重複生產,重複消費
原因:經過複雜的(等、資格)分析,發現被喚醒的執行緒沒有判斷標記就開始工作了(生成或消費)
導致了重複的生成和消費的發生
解決:
那就是被喚醒的執行緒必須判斷標記
使用while迴圈搞定
問題2:
死鎖了 。所有的執行緒都處於凍結狀態
原因:本方執行緒在喚醒時,又一次喚醒了本方執行緒。而本方執行緒迴圈判斷標記,又繼續等待
而導致所有的執行緒都等待了
解決:
希望本方如果喚醒了對方執行緒,就可以解決
可以使用notifyAll()方法
那不是全喚醒了嗎?是的,既有本方又有對方。但是本方醒後,會判斷標記繼續等待
這樣對方就有執行緒可以執行了
*/
public class ProduceConsumerDemo {
public static void main(String[] args) {
// 建立資源
Res res=new Res();
// 建立兩個任務
Producer producer=new Producer(res);
Customers customers=new Customers(res);
Thread t1=new Thread(producer);
Thread t2=new Thread(customers);
t1.start();
t2.start();
}
}
//描述資源
class Res{
private String name;
private int count=1;
//定義標記
private boolean flag;
//提供給商品賦值的方法
public synchronized void set(String name){
if(flag)//判斷標記為true,執行wait,為false,就生產
try {
wait();
} catch (InterruptedException e) {}
this.name = name +"--"+count;
count++;
System.out.println(Thread.currentThread().getName()+"...生產者....."+this.name);
//生產完畢,將標記改為notify()
flag=true;
//喚醒消費者
notify();
}
// 提供一個獲取商品的方法
public synchronized void get() {
if(!flag)
try {
wait();
} catch (InterruptedException e) {}
System.out.println(Thread.currentThread().getName()+"...消費者..."+this.name);
//將標記改為false
flag=false;
//喚醒消費者
notify();
}
}
//生產者
class Producer implements Runnable{
private Res res;
public Producer(Res res) {
this.res=res;
}
public void run(){
while(true){
res.set("麵包");
}
}
}
//消費者
class Customers implements Runnable{
private Res res;
public Customers(Res res) {
this.res=res;
}
public void run(){
while(true){
res.get();
}
}
}