线程通信用来保证线程协调运行,一般在做线程同步的时候才需要考虑线程通信的问题。

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()的返回值进行排序。

Java 线程通信的更多相关文章

  1. 第23章 java线程通信——生产者/消费者模型案例

    第23章 java线程通信--生产者/消费者模型案例 1.案例: package com.rocco; /** * 生产者消费者问题,涉及到几个类 * 第一,这个问题本身就是一个类,即主类 * 第二, ...

  2. Java线程通信

    Java线程通信 螣蛇乘雾,终为土灰. 多个线程协同工作完成某个任务时就会涉及到线程间通信问题.如何使各个线程之间同时执行,顺序执行.交叉执行等. 一.线程同时执行 创建两个线程a和b,两个线程内调用 ...

  3. java线程通信与协作小结 多线程中篇(十六)

      在锁与监视器中我们对Object中的方法进行了简单介绍 以监视器原理为核心,三个方法:wait,notify.notifyAll,可以完成线程之间的通信 当然,不会像“语言”似的,有多种多样的沟通 ...

  4. Java线程通信-生产者消费者问题

    线程通信示例——生产者消费者问题 这类问题描述了一种情况,假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者将仓库中的产品取走消费.假设仓库中没有产品,则生产者可以将 产品放入仓库,有 ...

  5. Java线程通信——wait() 和 notify()

    Object类中有关线程通信的方法有两个notify方法和三个wait方法,官方解释: void notify() Wakes up a single thread that is waiting o ...

  6. JAVA线程通信之生产者与消费者

    package cn.test.hf.test3; import java.util.concurrent.locks.Condition;import java.util.concurrent.lo ...

  7. Java线程入门第二篇

    Java线程通信方法 0.(why)每个线程都有自己的栈空间,我们要线程之间进行交流,合作共赢. 1.synchronized和volatile关键字 a)  看下面的synchronized关键字 ...

  8. java多线程-线程通信

    线程通信的目标是使线程间能够互相发送信号.另一方面,线程通信使线程能够等待其他线程的信号. 通过共享对象通信 忙等待 wait(),notify()和 notifyAll() 丢失的信号 假唤醒 多线 ...

  9. Java核心知识点学习----使用Condition控制线程通信

    一.需求 实现线程间的通信,主线程循环3次后,子线程2循环2次,子线程3循环3次,然后主线程接着循环3次,如此循环3次. 即:A->B->C---A->B->C---A-> ...

随机推荐

  1. JQuery01

    一:JQuery 1 JQuery知识 *:就是让我们学会调用JQ插件,其实内部就是对JS的封装. *:jquery里面有三个文件, 第2个和第3个其实里面的内容是一样的,只是第三个对其进行了压缩,使 ...

  2. 两个dropDownList和一个GridView的选择与显示

    很久没有写ASP.NET了,今天有看到论坛上一个问题:"两个dropDownList和一个GridView,已经进行了数据绑定,现在想让第一个下拉菜单的数据改变时,第二个下拉菜单自动变到相应 ...

  3. 损失函数(Loss Function) -1

    http://www.ics.uci.edu/~dramanan/teaching/ics273a_winter08/lectures/lecture14.pdf Loss Function 损失函数 ...

  4. Hack语言特性之类型化

    Hack最基础的特性就是类型标注.PHP5已经开始支持对象的类型化,PHP7也提供了标量类型化声明.Hack提供了全面的类型标注支持,与其typecher配合使用,还可以实现快速.前置静态类型验证. ...

  5. FNV哈希算法

    由来:FNV哈希算法全名为Fowler-Noll-Vo算法,是以三位发明人Glenn Fowler,Landon Curt Noll,Phong Vo的名字来命名的,最早在1991年提出. 特点和用途 ...

  6. JQuery的调用

    在head标签中引用一个JQuery的文件用以制作鼠标点击动画,(JQuery包可从网上下载)   JS包,脚本语言 <script language="javascript" ...

  7. html中代码高亮显示

    <html> <head> <meta http-equiv=”Content-Type” content=”text/html; charset=UTF-8″> ...

  8. Scalaz(6)- typeclass:Functor-just map

    Functor是范畴学(Category theory)里的概念.不过无须担心,我们在scala FP编程里并不需要先掌握范畴学知识的.在scalaz里,Functor就是一个普通的typeclass ...

  9. Swagger接入

    一 简介 Swagger是一个开源项目,用于描述和生成RestAPi的文档.可以帮助开发人员快速了解web服务的功能. 二  接入Swagger流程 1.在所在Module的pom.xml中,添加Sw ...

  10. Hibernate(三)__核心接口和类

    该图显示了核心接口类以及配置文件的关系层次,越往下越偏向底层数据库. 1. hibernate.cfg.xml文件 ①该文件主要用于指定各个参数,是hibernate核心文件 ②默认放在src目录下, ...