Java線程通信詳解
線程通信用來(lái)保證線程協(xié)調(diào)運(yùn)行,一般在做線程同步的時(shí)候才需要考慮線程通信的問(wèn)題。
1、傳統(tǒng)的線程通信
通常利用Objeclt類提供的三個(gè)方法:
- wait() 導(dǎo)致當(dāng)前線程等待,并釋放該同步監(jiān)視器的鎖定,直到其它線程調(diào)用該同步監(jiān)視器的notify()或者notifyAll()方法喚醒線程。
- notify(),喚醒在此同步監(jiān)視器上等待的線程,如果有多個(gè)會(huì)任意選擇一個(gè)喚醒
- notifyAll() 喚醒在此同步監(jiān)視器上等待的所有線程,這些線程通過(guò)調(diào)度競(jìng)爭(zhēng)資源后,某個(gè)線程獲取此同步監(jiān)視器的鎖,然后得以運(yùn)行。
這三個(gè)方法必須由同步監(jiān)視器對(duì)象調(diào)用,分為兩張情況:
同步方法時(shí),由于同步監(jiān)視器為this對(duì)象,所以可以直接調(diào)用這三個(gè)方法。
示例如下:
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) {
//實(shí)現(xiàn)兩個(gè)線程輪流對(duì)數(shù)據(jù)進(jìn)行加一操作
DataWrap dataWrap = new DataWrap();
new ThreadA(dataWrap).start();
new ThreadB(dataWrap).start();
}
}
同步代碼塊時(shí),需要使用監(jiān)視器對(duì)象調(diào)用這三個(gè)方法。
示例如下:
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) {
//實(shí)現(xiàn)兩個(gè)線程輪流對(duì)數(shù)據(jù)進(jìn)行加一操作
DataWrap dataWrap = new DataWrap();
new ThreadA(dataWrap).start();
new ThreadB(dataWrap).start();
}
}
2、使用Condition控制線程通信
當(dāng)使用Lock對(duì)象保證同步時(shí),則使用Condition對(duì)象來(lái)保證協(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) {
//實(shí)現(xiàn)兩個(gè)線程輪流對(duì)數(shù)據(jù)進(jìn)行加一操作
DataWrap dataWrap = new DataWrap();
new ThreadA(dataWrap).start();
new ThreadB(dataWrap).start();
}
}
其中Condition對(duì)象的await(), singal(),singalAll()分別對(duì)應(yīng)wait(),notify()和notifyAll()方法。
3、使用阻塞隊(duì)列BlockingQueue控制線程通信
BlockingQueue是Queue接口的子接口,主要用來(lái)做線程通信使用,它具有一個(gè)特征:當(dāng)生產(chǎn)者線程試圖向BlockingQueue中放入元素時(shí),如果隊(duì)列已滿,則該線程被阻塞;當(dāng)消費(fèi)者線程試圖從BlockingQueue中取出元素時(shí),如果隊(duì)列已空,則該線程被阻塞。這兩個(gè)特征分別對(duì)應(yīng)兩個(gè)支持阻塞的方法,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) {
///實(shí)現(xiàn)兩個(gè)線程輪流對(duì)數(shù)據(jù)進(jìn)行加一操作
DataWrap dataWrap = new DataWrap();
BlockingQueue<DataWrap> blockingQueue = new ArrayBlockingQueue<>(1);
new ThreadA(blockingQueue, "Consumer").start();
new ThreadB(blockingQueue, dataWrap, "Producer").start();
}
}
BlockingQueue共有五個(gè)實(shí)現(xiàn)類:
ArrayBlockingQueue 基于數(shù)組實(shí)現(xiàn)的BlockingQueue隊(duì)列
LinkedBlockingQueue 基于鏈表實(shí)現(xiàn)的BlockingQueue隊(duì)列
PriorityBlockingQueue 中元素需實(shí)現(xiàn)Comparable接口,其中元素的排序是按照Comparator進(jìn)行的定制排序。
SynchronousQueue 同步隊(duì)列,要求對(duì)該隊(duì)列的存取操作必須是交替進(jìn)行。
DelayQueue 集合元素必須實(shí)現(xiàn)Delay接口,隊(duì)列中元素排序按照Delay接口方法getDelay()的返回值進(jìn)行排序。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
那些年用httpclient時(shí)踩過(guò)的一些坑
這篇文章主要給大家介紹了關(guān)于那些年用httpclient時(shí)踩過(guò)的一些坑,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用httpclient具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05
mybatis創(chuàng)建項(xiàng)目報(bào)Invalid?bound?statement?(not?found)錯(cuò)誤解決方法
使用MyBatis能夠幫助我們將SQL語(yǔ)句和Java代碼分離,這篇文章主要給大家介紹了關(guān)于mybatis創(chuàng)建項(xiàng)目報(bào)Invalid?bound?statement?(not?found)錯(cuò)誤的解決方法,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-05-05
springboot啟動(dòng)時(shí)運(yùn)行代碼詳解
在本篇內(nèi)容中我們給大家整理了關(guān)于在springboot啟動(dòng)時(shí)運(yùn)行代碼的詳細(xì)圖文步驟以及需要注意的地方講解,有興趣的朋友們學(xué)習(xí)下。2019-06-06
java URL 獲取PHP JSON 數(shù)據(jù)
這篇文章主要介紹了java URL 獲取PHP JSON 數(shù)據(jù),需要的朋友可以參考下2016-04-04
Java8如何從一個(gè)Stream中過(guò)濾null值
這篇文章主要介紹了Java8如何從一個(gè)Stream中過(guò)濾null值,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05
SystemServer進(jìn)程啟動(dòng)過(guò)程解析
這篇文章主要為大家介紹了SystemServer進(jìn)程啟動(dòng)過(guò)程解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07
java實(shí)用小技巧之判斷l(xiāng)ist是否有重復(fù)項(xiàng)簡(jiǎn)單例子
這篇文章主要給大家介紹了關(guān)于java實(shí)用小技巧之判斷l(xiāng)ist是否有重復(fù)項(xiàng)的相關(guān)資料,在開(kāi)發(fā)工作中我們有時(shí)需要去判斷List集合中是否含有重復(fù)的元素,需要的朋友可以參考下2023-10-10
淺析Java語(yǔ)言中狀態(tài)模式的優(yōu)點(diǎn)
狀態(tài)模式允許對(duì)象在內(nèi)部狀態(tài)改變時(shí)改變它的行為,對(duì)象看起來(lái)好像修改了它的類。這個(gè)模式將狀態(tài)封裝成獨(dú)立的類,并將動(dòng)作委托到 代表當(dāng)前狀態(tài)的對(duì)象,我們知道行為會(huì)隨著內(nèi)部狀態(tài)而改變2023-02-02

