1. 程式人生 > >java學習第十二天之多執行緒死鎖和併發

java學習第十二天之多執行緒死鎖和併發

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();
        }       
    }
}