Java多線程-線程的交互

1、線程交互的基礎知識
void notify():喚醒在此對象監視器上等待的單個線程。
void notifyAll():喚醒在此對象監視器上等待的全部線程。
void wait():致使當前的線程等待,直到其餘線程調用此對象的 notify()方法或 notifyAll()方法。

固然,wait()還有另外兩個重載方法:
void wait(long timeout):致使當前的線程等待,直到其餘線程調用此對象的 notify()方法或 notifyAll()方法,或者超過指定的時間量。
void wait(long timeout, int nanos):致使當前的線程等待,直到其餘線程調用此對象的 notify()方法或 notifyAll()方法,或者其餘某個線程中斷當前線程,或者已超過某個實際時間量。ide

關於等待/通知,要記住的關鍵點是:
必須從同步代碼塊內調用wait()、notify()、notifyAll()方法。線程不能調用對象上等待或通知的方法,除非它擁有那個對象的鎖。this

wait()、notify()、notifyAll()都是Object的實例方法。與每一個對象具備鎖同樣,每一個對象能夠有一個線程列表,他們等待來自該信號(通知)。線程經過執行對象上的wait()方法得到這個等待列表。從那時候起,它再也不執行任何其餘指令,直到調用對象的notify()方法爲止。若是多個線程在同一個對象上等待,則將只選擇一個線程(不保證以何種順序)繼續執行。若是沒有線程等待,則不採起任何特殊操做。spa

例子線程

package cn.thread;

/**
 * 計算1+2+3 ... +100的和
 * 
 * @author 林計欽
 * @version 1.0 2013-7-23 上午10:06:04
 */
public class ThreadSum extends Thread {
    int total = 0;

    @Override
    public void run() {

        synchronized (this) {
            for (int i = 0; i < 101; i++) {
                total += i;
            }
            //(完成計算了)喚醒在此對象監視器上等待的單個線程,在本例中線程ThreadInteractionTest被喚醒
            notify();
        }

    }
}
package cn.thread;

/**
 * 線程的交互
 * 
 * @author 林計欽
 * @version 1.0 2013-7-23 上午10:04:11
 */
public class ThreadInteractionTest {
    public static void main(String[] args) {
        
        ThreadSum sum = new ThreadSum();
        // 啓動計算線程
        sum.start();
        // 線程ThreadInteractionTest擁有sum對象上的鎖。
        // 線程爲了調用wait()或notify()方法,該線程ThreadInteractionTest必須是那個對象鎖的擁有者
        synchronized (sum) {
            try {
                System.out.println("等待對象sum完成計算。。。");
                // 當前線程ThreadInteractionTest等待
                sum.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("sum對象計算的總和是:" + sum.total);
        }
        
    }
}
等待對象sum完成計算。。。
sum對象計算的總和是:5050

注意:當在對象上調用wait()方法時,執行該代碼的線程當即放棄它在對象上的鎖。然而調用notify()時,並不意味着這時線程會放棄其鎖。若是線程仍然在完成同步代碼,則線程在移出以前不會放棄鎖。所以,只要調用notify()並不意味着這時該鎖變得可用。

2、多個線程在等待一個對象鎖時使用notifyAll()
在多數狀況下,最好通知等待某個對象的全部線程。若是這樣作,能夠在對象上使用notifyAll()讓全部在此對象上等待的線程衝出等待區,返回到可運行狀態。code

package cn.thread;

/**
 * 計算1+2+3 ... +100的和
 * 
 * @author 林計欽
 * @version 1.0 2013-7-23 上午10:06:04
 */
public class ThreadSum2 extends Thread {
    int total = 0;

    @Override
    public void run() {

        synchronized (this) {
            for (int i = 0; i < 101; i++) {
                total += i;
            }
            //通知全部在此對象上等待的線程 
            notifyAll();
        }

    }
}
package cn.thread;


/**
 * 線程的交互
 * 
 * @author 林計欽
 * @version 1.0 2013-7-23 上午10:04:11
 */
public class ThreadInteractionTest2 extends Thread{
    ThreadSum2 sum;
    
    public ThreadInteractionTest2(ThreadSum2 sum){
        this.sum=sum;
    }
    
    @Override
    public void run() {
        synchronized (sum) {
            try {
                System.out.println("等待對象sum完成計算。。。");
                // 當前線程ThreadInteractionTest等待
                sum.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("sum對象計算的總和是:" + sum.total);
        }
    }
    
    public static void main(String[] args) {
        ThreadSum2 sum = new ThreadSum2();
        
        //啓動三個線程,分別獲取計算結果 
        new ThreadInteractionTest2(sum).start();
        new ThreadInteractionTest2(sum).start();
        new ThreadInteractionTest2(sum).start();
        
        // 啓動計算線程
        sum.start();
        
        
    }
}
等待對象sum完成計算。。。
等待對象sum完成計算。。。
等待對象sum完成計算。。。
sum對象計算的總和是:5050
sum對象計算的總和是:5050
sum對象計算的總和是:5050

談一下synchronized和wait()、notify()等的關係:
一、有synchronized的地方不必定有wait,notify
二、有wait,notify的地方必有synchronized.這是由於wait和notify不是屬於線程類,而是每個對象都具備的方法,並且,這兩個方法都和對象鎖有關,有鎖的地方,必有synchronized。
另外,注意一點:若是要把notify和wait方法放在一塊兒用的話,必須先調用notify後調用wait,由於若是調用完wait,該線程就已經不是currentthread了。對象

相關文章
相關標籤/搜索