目錄
Java中線程通信方式
1. 同步
這裏的同步是指多個線程通過synchronized關鍵字這種方式來實現線程間的通信,簡單說就是,兩個線程,一個線程執行完了,另一個才能執行。
public class MyObject {
synchronized public void methodA() {
//do something....
}
synchronized public void methodB() {
//do some other thing
}
}
public class ThreadA extends Thread {
private MyObject object;
//省略構造方法
@Override
public void run() {
object.methodA();
}
}
public class ThreadB extends Thread {
private MyObject object;
//省略構造方法
@Override
public void run() {
object.methodB();
}
}
public class Run {
public static void main(String[] args) {
MyObject object = new MyObject();
//線程A與線程B 持有的是同一個對象:object
ThreadA a = new ThreadA(object);
ThreadB b = new ThreadB(object);
a.start();
b.start();
}
}
線程A和線程B持有同一個MyObject類的對象object,儘管這兩個需要調用不同的方法,但是他們是同步執行的,線程B需要等待線程A執行完methodA()方法後,它才能執行methodB()方法。這樣線程A和線程B就實現了通信。
這種方式本質上就是“共享內存”式的通信。多個線程需要訪問同一個變量,誰拿到鎖,誰就可以執行
2. Wait / notify機制
//共享資源對象
public class Can {
private String type;
private String date;
// 表示檢查當前共享資源狀態是否爲空
private boolean isEmpty = true;
/**
* 生產者向共享資源中存儲數據
*
* @param type
* 存儲的罐頭類型
* @param date
* 存儲罐頭的生產日期批次
*/
synchronized public void push(String type, String date) {
try {
while (!isEmpty) {//當前共享資源狀態不空,等待消費者來消費
//使用同步鎖對象調用,表示當前線程釋放同步鎖,進入等待池(休眠)
//只能等待被其他線程喚醒
this.wait();
}
//-----生產開始-----
this.type = type;
Thread.sleep(10);
this.date = date;
//-----生產結束-----
//修改共享資源狀態不爲空
isEmpty=false;
//喚醒一個消費者
this.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 消費者從共享資源中取出數據並打印
*/
synchronized public void popup() {
try {
while(isEmpty){
//當共享資源狀態爲空,釋放同步鎖,進入等待吃(休眠)
//等待生產者生產,然後被喚醒
wait();
}
Thread.sleep(10);
//-----消費開始-----
System.out.println(this.type + "--->" + this.date);
//-----消費結束-----
//修改共享資源狀態爲空
isEmpty=true;
//喚醒一個生產者生產
this.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Test {
public static void main(String[] args) {
Can can = new Can();
new Thread(new Producer(can)).start();
new Thread(new Consumer(can)).start();
}
}
可以看到兩個線程生產者和消費者,剛開始沒有罐頭,消費者處於等待狀態,生產者就開始生產罐頭,此時有罐頭了,喚醒消費者,自己進入阻塞狀態,消費者消費空了又把生產者喚醒,一直循環這個過程。
上面兩種通信方式,都屬於共享內存的通信方式,都有一個共享變量,通過Sychronized同步鎖,wait和notify來通知。
3. 利用volatile
volatile修飾的變量值直接存在主內存裏面,子線程對該變量的讀寫直接寫住內存,而不是像其它變量一樣在local thread裏面產生一份copy。volatile能保證所修飾的變量對於多個線程可見性,即只要被修改,其它線程讀到的一定是最新的值。
4. 利用AtomicInteger
和volatile類似
5. 管道通信
Java中有各種各樣的輸入、輸出流(Stream),其中管道流(pipeStream)是一種特殊的流,用於在不同線程間直接傳送數據。Java中的Stream是單向的,所以在兩個線程中分別建了一個PipedInputStream、PipedOutputStream。