线程通信用来保证线程协调运行,一般在做线程同步的时候才需要考虑线程通信的问题。
1、传统的线程通信
通常利用Objeclt类提供的三个方法:
这三个方法必须由同步监视器对象调用,分为两张情况:
同步方法时,由于同步监视器为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()的返回值进行排序。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。
主要内容:1 什么是Java线程通信,2 线程间通信的过程分析,3 线程间通信的疑问,4 wait()和sleep()的区别,5 Java线程通信的例子1 什么是Java线程通信 线程间通信或协作就是允许同步线程彼此通信。 线程间通信是一种机制,其中一个线程在其关键部分中暂停运行,并允许另一个线程进入(或锁定)在同一关键部分中执行,这是通过以下Object类的方法实现的: wait() notify() notifyAll() 1.1 wait()方法 使当前线程释放锁定,并等待直到另一个线程为
本文向大家介绍Java多线程中线程间的通信实例详解,包括了Java多线程中线程间的通信实例详解的使用技巧和注意事项,需要的朋友参考一下 Java多线程中线程间的通信 一、使用while方式来实现线程之间的通信 程序输出: 理解:线程Thread2不停地通过while语句检测这个条件(list.size()==5)是否成立 ,从而实现了线程间的通信。但是这种方式会浪费CPU资源。 二、wait no
本文向大家介绍Java多线程通信实现方式详解,包括了Java多线程通信实现方式详解的使用技巧和注意事项,需要的朋友参考一下 这篇文章主要介绍了Java多线程通信实现方式详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 线程通信的方式: 1、共享变量 线程间通信可以通过发送信号,发送信号的一个简单方式是在共享对象的变量里设置信号值。线程A在一个同
问题内容: Java上下文中的线程和进程之间有什么区别?用Java如何实现进程间通信和线程间通信?请给我指出一些现实生活中的例子。 问题答案: 根本的区别是线程位于相同的地址空间中,而进程位于不同的地址空间中。这意味着线程间通信是关于传递对对象的引用以及更改共享对象,而进程是关于传递对象的序列化副本。 在实践中,Java线程间通信可以实现为对共享对象进行简单的Java方法调用,并引入适当的同步。或
本文向大家介绍java 多线程-线程通信实例讲解,包括了java 多线程-线程通信实例讲解的使用技巧和注意事项,需要的朋友参考一下 线程通信的目标是使线程间能够互相发送信号。另一方面,线程通信使线程能够等待其他线程的信号。 通过共享对象通信 忙等待 wait(),notify()和 notifyAll() 丢失的信号 假唤醒 多线程等待相同信号 不要对常量字符串或全局对象调用 wait() 通过共
问题内容: Java相互依赖的线程如何通信? 例如,我正在使用需要来自其他线程的数据的线程构建Web搜寻器。 问题答案: 这取决于通信的性质。 它是双工的吗(即A与B对话,B与A对话)? 是数据通信还是 完成 通信? 等等。 线程间通信的最简单,最可取的形式就是等待其他线程的完成。使用以下命令最容易做到: 在第一个任务完成之前,第二个任务将不会执行。 Java 5+具有 许多 并发实用程序来处理这