Java线程通信详解
线程通信用来保证线程协调运行,一般在做线程同步的时候才需要考虑线程通信的问题。
1、传统的线程通信
通常利用objeclt类提供的三个方法:
- wait() 导致当前线程等待,并释放该同步监视器的锁定,直到其它线程调用该同步监视器的notify()或者notifyall()方法唤醒线程。
- notify(),唤醒在此同步监视器上等待的线程,如果有多个会任意选择一个唤醒
- notifyall() 唤醒在此同步监视器上等待的所有线程,这些线程通过调度竞争资源后,某个线程获取此同步监视器的锁,然后得以运行。
这三个方法必须由同步监视器对象调用,分为两张情况:
同步方法时,由于同步监视器为this对象,所以可以直接调用这三个方法。
示例如下:
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) { //实现两个线程轮流对数据进行加一操作 datawrap datawrap = new datawrap(); new threada(datawrap).start(); new threadb(datawrap).start(); } }
同步代码块时,需要使用监视器对象调用这三个方法。
示例如下:
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) { //实现两个线程轮流对数据进行加一操作 datawrap datawrap = new datawrap(); new threada(datawrap).start(); new threadb(datawrap).start(); } }
2、使用condition控制线程通信
当使用lock对象保证同步时,则使用condition对象来保证协调。
示例如下:
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) { //实现两个线程轮流对数据进行加一操作 datawrap datawrap = new datawrap(); new threada(datawrap).start(); new threadb(datawrap).start(); } }
其中condition对象的await(), singal(),singalall()分别对应wait(),notify()和notifyall()方法。
3、使用阻塞队列blockingqueue控制线程通信
blockingqueue是queue接口的子接口,主要用来做线程通信使用,它具有一个特征:当生产者线程试图向blockingqueue中放入元素时,如果队列已满,则该线程被阻塞;当消费者线程试图从blockingqueue中取出元素时,如果队列已空,则该线程被阻塞。这两个特征分别对应两个支持阻塞的方法,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) { ///实现两个线程轮流对数据进行加一操作 datawrap datawrap = new datawrap(); blockingqueue<datawrap> blockingqueue = new arrayblockingqueue<>(1); new threada(blockingqueue, "consumer").start(); new threadb(blockingqueue, datawrap, "producer").start(); } }
blockingqueue共有五个实现类:
arrayblockingqueue 基于数组实现的blockingqueue队列
linkedblockingqueue 基于链表实现的blockingqueue队列
priorityblockingqueue 中元素需实现comparable接口,其中元素的排序是按照comparator进行的定制排序。
synchronousqueue 同步队列,要求对该队列的存取操作必须是交替进行。
delayqueue 集合元素必须实现delay接口,队列中元素排序按照delay接口方法getdelay()的返回值进行排序。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。