Java线程通信详解
线程通信用来保证线程协调运行,一般在做线程同步的时候才需要考虑线程通信的问题。
1、传统的线程通信
通常利用Objeclt类提供的三个方法:
- wait()导致当前线程等待,并释放该同步监视器的锁定,直到其它线程调用该同步监视器的notify()或者notifyAll()方法唤醒线程。
- notify(),唤醒在此同步监视器上等待的线程,如果有多个会任意选择一个唤醒
- notifyAll()唤醒在此同步监视器上等待的所有线程,这些线程通过调度竞争资源后,某个线程获取此同步监视器的锁,然后得以运行。
这三个方法必须由同步监视器对象调用,分为两张情况:
同步方法时,由于同步监视器为this对象,所以可以直接调用这三个方法。
示例如下:
publicclassSyncMethodThreadCommunication{
staticclassDataWrap{
intdata=0;
booleanflag=false;
publicsynchronizedvoidaddThreadA(){
if(flag){
try{
wait();
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
data++;
System.out.println(Thread.currentThread().getName()+""+data);
flag=true;
notify();
}
publicsynchronizedvoidaddThreadB(){
if(!flag){
try{
wait();
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
data++;
System.out.println(Thread.currentThread().getName()+""+data);
flag=false;
notify();
}
}
staticclassThreadAextendsThread{
privateDataWrapdata;
publicThreadA(DataWrapdataWrap){
this.data=dataWrap;
}
@Override
publicvoidrun(){
for(inti=0;i<10;i++){
data.addThreadA();
}
}
}
staticclassThreadBextendsThread{
privateDataWrapdata;
publicThreadB(DataWrapdataWrap){
this.data=dataWrap;
}
@Override
publicvoidrun(){
for(inti=0;i<10;i++){
data.addThreadB();
}
}
}
publicstaticvoidmain(String[]args){
//实现两个线程轮流对数据进行加一操作
DataWrapdataWrap=newDataWrap();
newThreadA(dataWrap).start();
newThreadB(dataWrap).start();
}
}
同步代码块时,需要使用监视器对象调用这三个方法。
示例如下:
publicclassSyncBlockThreadComminication{
staticclassDataWrap{
booleanflag;
intdata;
}
staticclassThreadAextendsThread{
DataWrapdataWrap;
publicThreadA(DataWrapdataWrap){
this.dataWrap=dataWrap;
}
@Override
publicvoidrun(){
for(inti=0;i<10;i++){
synchronized(dataWrap){
if(dataWrap.flag){
try{
dataWrap.wait();
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
dataWrap.data++;
System.out.println(getName()+""+dataWrap.data);
dataWrap.flag=true;
dataWrap.notify();
}
}
}
}
staticclassThreadBextendsThread{
DataWrapdataWrap;
publicThreadB(DataWrapdataWrap){
this.dataWrap=dataWrap;
}
@Override
publicvoidrun(){
for(inti=0;i<10;i++){
synchronized(dataWrap){
if(!dataWrap.flag){
try{
dataWrap.wait();
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
dataWrap.data++;
System.out.println(getName()+""+dataWrap.data);
dataWrap.flag=false;
dataWrap.notify();
}
}
}
}
publicstaticvoidmain(String[]args){
//实现两个线程轮流对数据进行加一操作
DataWrapdataWrap=newDataWrap();
newThreadA(dataWrap).start();
newThreadB(dataWrap).start();
}
}
2、使用Condition控制线程通信
当使用Lock对象保证同步时,则使用Condition对象来保证协调。
示例如下:
importjava.util.concurrent.locks.Condition;
importjava.util.concurrent.locks.Lock;
importjava.util.concurrent.locks.ReentrantLock;
importcom.sun.media.sound.RIFFInvalidDataException;
importjavafx.scene.chart.PieChart.Data;
publicclassSyncLockThreadCommunication{
staticclassDataWrap{
intdata;
booleanflag;
privatefinalLocklock=newReentrantLock();
privatefinalConditioncondition=lock.newCondition();
publicvoidaddThreadA(){
lock.lock();
try{
if(flag){
try{
condition.await();
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
data++;
System.out.println(Thread.currentThread().getName()+""+data);
flag=true;
condition.signal();
}finally{
lock.unlock();
}
}
publicvoidaddThreadB(){
lock.lock();
try{
if(!flag){
try{
condition.await();
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
data++;
System.out.println(Thread.currentThread().getName()+""+data);
flag=false;
condition.signal();
}finally{
lock.unlock();
}
}
}
staticclassThreadAextendsThread{
DataWrapdataWrap;
publicThreadA(DataWrapdataWrap){
this.dataWrap=dataWrap;
}
@Override
publicvoidrun(){
for(inti=0;i<10;i++){
dataWrap.addThreadA();
}
}
}
staticclassThreadBextendsThread{
DataWrapdataWrap;
publicThreadB(DataWrapdataWrap){
this.dataWrap=dataWrap;
}
@Override
publicvoidrun(){
for(inti=0;i<10;i++){
dataWrap.addThreadB();
}
}
}
publicstaticvoidmain(String[]args){
//实现两个线程轮流对数据进行加一操作
DataWrapdataWrap=newDataWrap();
newThreadA(dataWrap).start();
newThreadB(dataWrap).start();
}
}
其中Condition对象的await(),singal(),singalAll()分别对应wait(),notify()和notifyAll()方法。
3、使用阻塞队列BlockingQueue控制线程通信
BlockingQueue是Queue接口的子接口,主要用来做线程通信使用,它具有一个特征:当生产者线程试图向BlockingQueue中放入元素时,如果队列已满,则该线程被阻塞;当消费者线程试图从BlockingQueue中取出元素时,如果队列已空,则该线程被阻塞。这两个特征分别对应两个支持阻塞的方法,put(Ee)和take()
示例如下:
importjava.util.concurrent.ArrayBlockingQueue;
importjava.util.concurrent.BlockingQueue;
publicclassBlockingQueueThreadComminication{
staticclassDataWrap{
intdata;
}
staticclassThreadAextendsThread{
privateBlockingQueue<DataWrap>blockingQueue;
publicThreadA(BlockingQueue<DataWrap>blockingQueue,Stringname){
super(name);
this.blockingQueue=blockingQueue;
}
@Override
publicvoidrun(){
for(inti=0;i<100;i++){
try{
DataWrapdataWrap=blockingQueue.take();
dataWrap.data++;
System.out.println(getName()+""+dataWrap.data);
sleep(1000);
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
}
staticclassThreadBextendsThread{
privateBlockingQueue<DataWrap>blockingQueue;
privateDataWrapdataWrap;
publicThreadB(BlockingQueue<DataWrap>blockingQueue,DataWrapdataWrap,Stringname){
super(name);
this.blockingQueue=blockingQueue;
this.dataWrap=dataWrap;
}
@Override
publicvoidrun(){
for(inti=0;i<100;i++){
try{
dataWrap.data++;
System.out.println(getName()+""+dataWrap.data);
blockingQueue.put(dataWrap);
sleep(1000);
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
}
publicstaticvoidmain(String[]args){
///实现两个线程轮流对数据进行加一操作
DataWrapdataWrap=newDataWrap();
BlockingQueue<DataWrap>blockingQueue=newArrayBlockingQueue<>(1);
newThreadA(blockingQueue,"Consumer").start();
newThreadB(blockingQueue,dataWrap,"Producer").start();
}
}
BlockingQueue共有五个实现类:
ArrayBlockingQueue基于数组实现的BlockingQueue队列
LinkedBlockingQueue基于链表实现的BlockingQueue队列
PriorityBlockingQueue中元素需实现Comparable接口,其中元素的排序是按照Comparator进行的定制排序。
SynchronousQueue同步队列,要求对该队列的存取操作必须是交替进行。
DelayQueue集合元素必须实现Delay接口,队列中元素排序按照Delay接口方法getDelay()的返回值进行排序。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。