天天看點

線程間通信及其安全問題

線程間的通行與等待喚醒機制舉例:

 一、兩個線程:

/**
 * @author flame
 * @createDate 2012-1-3
 * 線程間的通信:
 * 首先,有一個資源,提供存取對象
 * 一個線程往裡面注入資源
 * 另一個線程從裡面讀取資源
 * 多個線程操作同一個個資料,不同的是操作動作不同
 * 喚醒機制:
 * 為避免一個資源注入一般就被另一個資源所讀取,是以需要采用喚醒機制。
 * 原理:注入時,注入線程執行狀态,讀取線程等待狀态;注入後,注入線程等待狀态,讀取線程執行狀态。
 * wait()等待
 * notify()喚醒單一線程
 * notifyAll()喚醒所有線程
 * 喚醒隻能喚醒同一個鎖的等待線程,不能喚醒不同鎖的等待線程,也就是說等待線程的鎖和喚醒線程的鎖必須同一個。
 */
/**
 * 資源,提供姓名和性别
 * @author flame
 * @createDate 2012-1-3
 */
class Result
{
    private String name;
    private String sex;
    private boolean flag = false; 
    public synchronized void set(String name, String sex)
    {
        if(flag)
            try{this.wait();}catch(InterruptedException ex){}
        this.name = name;
        this.sex = sex;
        flag = true;
        this.notify();        
    }
    public synchronized void get()
    {
        if(!flag)
            try{this.wait();}catch(InterruptedException ex){}
        System.out.println(this.name+"...."+this.sex);
        this.flag = false;
        this.notify();
    }
}
/**
 * 注入資源線程
 * @author flame
 * @createDate 2012-1-3
 */
class InputInfo implements Runnable
{
    private Result r;             //聲明資源類
    public InputInfo(Result r)    //傳入一個資源類,以是得資源為同個資源
    {
        this.r = r;
    }
    public void run()
    {        
        int i= 0,j =0;
        while(i <=500)
        {            
            if(j == 0)
                r.set("flame", "man");                
            else
                r.set("火", "男");                
            j = (j+1)%2;            
            i++;                                
        }        
    }
}
/**
 * 擷取資源中的資料
 * @author flame
 * @createDate 2012-1-3
 */
class OutputInfo implements Runnable
{
    private Result r;
    public OutputInfo(Result r)
    {
        this.r = r;
    }
    public void run()
    {
        int i = 0;
        while(i<500)
        {
            r.get();
            i++;                
        }        
    }
}
public class communcationThreadDemo {

    /**
     * 啟動線程
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Result r = new Result();
        new Thread(new InputInfo(r)).start();
        new Thread(new OutputInfo(r)).start();
        
    }

}
           

二、多線程 (生産者與消費者)

/**
 * 生産者與消費者舉例
 * 當出現多個線程時,喚醒機制的另一種解決方式
 * @author flame
 * @createDate 2012-1-3
 */


/**
 * 資源類
 * 初始化資源對象
 * 控制資源注入和輸出線程
 * @author flame
 * @createDate 2012-1-3
 */
class Ruselt
{
    private String name;
    private int count =0;
    private boolean flag = false;
    public synchronized void set(String name)
    {
        while(flag)
            try{
                this.wait();
            }catch(InterruptedException ex)
            {
                System.out.println(ex.getMessage());
            }
        this.name = name +"***----***"+count++;
        System.out.println(Thread.currentThread().getName()+"******生産者******"+this.name);
        this.flag = true;
        this.notifyAll();
    }
    public synchronized void get()
    {
        while(!flag)        //此處如果采用if語句判斷,會使得當以線程判斷通過而放棄資格後,在蘇醒時會不再經過判斷而繼續執行下面的代碼
            try{
                this.wait();
            }catch(InterruptedException ex)
            {
                System.out.println(ex.getMessage());
            }
        System.out.println(Thread.currentThread().getName()+"=====消費者================="+name);
        this.flag = false;
        this.notifyAll();     //喚醒所有線程,避免全部線程處于等待狀态
    }
}
class InputComm implements Runnable
{
    private Ruselt r;
    public InputComm(Ruselt r)
    {
        this.r = r;
    }
    public void run()
    {
        int i=0;
        while(i<500)
        {
            r.set("商品");
            i++;
        }
    }
}
class OutputComm implements Runnable
{
    private Ruselt r;
    public OutputComm(Ruselt r)
    {
        this.r = r;
    }
    public void run()
    {
        int i=0;
        while(i<500)
        {
            r.get();
            i++;
        }
    }
}
public class moreThreadDemo {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Ruselt r = new Ruselt();
        new Thread(new InputComm(r)).start();
        new Thread(new OutputComm(r)).start();
    }

}