Java線程通信詳解
線程通信用來保證線程協(xié)調(diào)運行,一般在做線程同步的時候才需要考慮線程通信的問題。
1、傳統(tǒng)的線程通信
通常利用Objeclt類提供的三個方法:
- wait() 導(dǎo)致當(dāng)前線程等待,并釋放該同步監(jiān)視器的鎖定,直到其它線程調(diào)用該同步監(jiān)視器的notify()或者notifyAll()方法喚醒線程。
- notify(),喚醒在此同步監(jiān)視器上等待的線程,如果有多個會任意選擇一個喚醒
- notifyAll() 喚醒在此同步監(jiān)視器上等待的所有線程,這些線程通過調(diào)度競爭資源后,某個線程獲取此同步監(jiān)視器的鎖,然后得以運行。
這三個方法必須由同步監(jiān)視器對象調(diào)用,分為兩張情況:
同步方法時,由于同步監(jiān)視器為this對象,所以可以直接調(diào)用這三個方法。
示例如下:
public class SyncMethodThreadCommunication { static class DataWrap{ int data = 0; boolean flag = false; public synchronized void addThreadA(){ if (flag) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } data++; System.out.println(Thread.currentThread().getName() + " " + data); flag = true; notify(); } public synchronized void addThreadB() { if (!flag) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } data++; System.out.println(Thread.currentThread().getName() + " " + data); flag = false; notify(); } } static class ThreadA extends Thread { private DataWrap data; public ThreadA(DataWrap dataWrap) { this.data = dataWrap; } @Override public void run() { for (int i = 0; i < 10; i++) { data.addThreadA(); } } } static class ThreadB extends Thread { private DataWrap data; public ThreadB(DataWrap dataWrap) { this.data = dataWrap; } @Override public void run() { for (int i = 0; i < 10; i++) { data.addThreadB(); } } } public static void main(String[] args) { //實現(xiàn)兩個線程輪流對數(shù)據(jù)進行加一操作 DataWrap dataWrap = new DataWrap(); new ThreadA(dataWrap).start(); new ThreadB(dataWrap).start(); } }
同步代碼塊時,需要使用監(jiān)視器對象調(diào)用這三個方法。
示例如下:
public class SyncBlockThreadComminication { static class DataWrap{ boolean flag; int data; } static class ThreadA extends Thread{ DataWrap dataWrap; public ThreadA(DataWrap dataWrap){ this.dataWrap = dataWrap; } @Override public void run() { for(int i = 0 ; i < 10; i++) { synchronized (dataWrap) { if (dataWrap.flag) { try { dataWrap.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } dataWrap.data++; System.out.println(getName() + " " + dataWrap.data); dataWrap.flag = true; dataWrap.notify(); } } } } static class ThreadB extends Thread{ DataWrap dataWrap; public ThreadB(DataWrap dataWrap){ this.dataWrap = dataWrap; } @Override public void run() { for (int i = 0; i < 10; i++) { synchronized (dataWrap) { if (!dataWrap.flag) { try { dataWrap.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } dataWrap.data++; System.out.println(getName() + " " + dataWrap.data); dataWrap.flag = false; dataWrap.notify(); } } } } public static void main(String[] args) { //實現(xiàn)兩個線程輪流對數(shù)據(jù)進行加一操作 DataWrap dataWrap = new DataWrap(); new ThreadA(dataWrap).start(); new ThreadB(dataWrap).start(); } }
2、使用Condition控制線程通信
當(dāng)使用Lock對象保證同步時,則使用Condition對象來保證協(xié)調(diào)。
示例如下:
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import com.sun.media.sound.RIFFInvalidDataException; import javafx.scene.chart.PieChart.Data; public class SyncLockThreadCommunication { static class DataWrap { int data; boolean flag; private final Lock lock = new ReentrantLock(); private final Condition condition = lock.newCondition(); public void addThreadA() { lock.lock(); try { if (flag) { try { condition.await(); } catch (InterruptedException e) { e.printStackTrace(); } } data++; System.out.println(Thread.currentThread().getName() + " " + data); flag = true; condition.signal(); } finally { lock.unlock(); } } public void addThreadB() { lock.lock(); try { if (!flag) { try { condition.await(); } catch (InterruptedException e) { e.printStackTrace(); } } data++; System.out.println(Thread.currentThread().getName() + " " + data); flag = false; condition.signal(); } finally { lock.unlock(); } } } static class ThreadA extends Thread{ DataWrap dataWrap; public ThreadA(DataWrap dataWrap) { this.dataWrap = dataWrap; } @Override public void run() { for (int i = 0; i < 10; i++) { dataWrap.addThreadA(); } } } static class ThreadB extends Thread{ DataWrap dataWrap; public ThreadB(DataWrap dataWrap) { this.dataWrap = dataWrap; } @Override public void run() { for (int i = 0; i < 10; i++) { dataWrap.addThreadB(); } } } public static void main(String[] args) { //實現(xiàn)兩個線程輪流對數(shù)據(jù)進行加一操作 DataWrap dataWrap = new DataWrap(); new ThreadA(dataWrap).start(); new ThreadB(dataWrap).start(); } }
其中Condition對象的await(), singal(),singalAll()分別對應(yīng)wait(),notify()和notifyAll()方法。
3、使用阻塞隊列BlockingQueue控制線程通信
BlockingQueue是Queue接口的子接口,主要用來做線程通信使用,它具有一個特征:當(dāng)生產(chǎn)者線程試圖向BlockingQueue中放入元素時,如果隊列已滿,則該線程被阻塞;當(dāng)消費者線程試圖從BlockingQueue中取出元素時,如果隊列已空,則該線程被阻塞。這兩個特征分別對應(yīng)兩個支持阻塞的方法,put(E e)和take()
示例如下:
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; public class BlockingQueueThreadComminication { static class DataWrap{ int data; } static class ThreadA extends Thread{ private BlockingQueue<DataWrap> blockingQueue; public ThreadA(BlockingQueue<DataWrap> blockingQueue, String name) { super(name); this.blockingQueue = blockingQueue; } @Override public void run() { for (int i = 0; i < 100; i++) { try { DataWrap dataWrap = blockingQueue.take(); dataWrap.data++; System.out.println(getName() + " " + dataWrap.data); sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } static class ThreadB extends Thread{ private BlockingQueue<DataWrap> blockingQueue; private DataWrap dataWrap; public ThreadB(BlockingQueue<DataWrap> blockingQueue, DataWrap dataWrap, String name) { super(name); this.blockingQueue = blockingQueue; this.dataWrap = dataWrap; } @Override public void run() { for (int i = 0; i < 100; i++) { try { dataWrap.data++; System.out.println(getName() + " " + dataWrap.data); blockingQueue.put(dataWrap); sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) { ///實現(xiàn)兩個線程輪流對數(shù)據(jù)進行加一操作 DataWrap dataWrap = new DataWrap(); BlockingQueue<DataWrap> blockingQueue = new ArrayBlockingQueue<>(1); new ThreadA(blockingQueue, "Consumer").start(); new ThreadB(blockingQueue, dataWrap, "Producer").start(); } }
BlockingQueue共有五個實現(xiàn)類:
ArrayBlockingQueue 基于數(shù)組實現(xiàn)的BlockingQueue隊列
LinkedBlockingQueue 基于鏈表實現(xiàn)的BlockingQueue隊列
PriorityBlockingQueue 中元素需實現(xiàn)Comparable接口,其中元素的排序是按照Comparator進行的定制排序。
SynchronousQueue 同步隊列,要求對該隊列的存取操作必須是交替進行。
DelayQueue 集合元素必須實現(xiàn)Delay接口,隊列中元素排序按照Delay接口方法getDelay()的返回值進行排序。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
mybatis創(chuàng)建項目報Invalid?bound?statement?(not?found)錯誤解決方法
使用MyBatis能夠幫助我們將SQL語句和Java代碼分離,這篇文章主要給大家介紹了關(guān)于mybatis創(chuàng)建項目報Invalid?bound?statement?(not?found)錯誤的解決方法,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-05-05java URL 獲取PHP JSON 數(shù)據(jù)
這篇文章主要介紹了java URL 獲取PHP JSON 數(shù)據(jù),需要的朋友可以參考下2016-04-04java實用小技巧之判斷l(xiāng)ist是否有重復(fù)項簡單例子
這篇文章主要給大家介紹了關(guān)于java實用小技巧之判斷l(xiāng)ist是否有重復(fù)項的相關(guān)資料,在開發(fā)工作中我們有時需要去判斷List集合中是否含有重復(fù)的元素,需要的朋友可以參考下2023-10-10