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

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. 【SQL】靠谱的TRIM函数,附赠过程一枚

    SQL中有LTRIM和RTRIM这两个函数分别用于去除字符串的首.尾空格,缺乏常见的能同时去除首尾的TRIM函数,另外,这俩函数都只对[空格]有效,所以如果首尾是制表符.换行符等等[空白],它们是不处 ...

  2. 一个通过JSONP跨域调用WCF REST服务的例子(以jQuery为例)

    JSONP(JSON with Padding)可以看成是JSON的一种“使用模式”,用以解决“跨域访问”的问题,这篇简单的文章给出一个简单的例子用于模拟如何通过jQuery以JSONP的访问调用一个 ...

  3. Linux安装JDK1.8

    1. 安装前,最好先删除Linux自带的OpenJDK: (1)运行java-version,会发现Linux自带的OpenJDK,运行rpm -qa | grep OpenJDK,找出自带的Open ...

  4. 利用navigator对象在浏览器中检查插件

    利用navigator对象在浏览器中检查插件,实现的代码如下. // IE4+.firefox.chrome.safari.opera中,利用navigator检测插件 ,name为插件的名字 fun ...

  5. Delphi Berlin 10.1 for 小米平板2 (Win 10) 电子罗盘测试

    Windows 10 下没有 Sensor.HeadingXSensor.HeadingYSensor.HeadingZ 需改用 Sensor.CompMagHeading

  6. MVC-自定义过滤器

    APS.NET MVC中的每一个请求,都会分配给相应的控制器和对应的行为方法去处理,而在这些处理的前前后后如果想再加一些额外的逻辑处理.这时候就用到了过滤器. 自定义过滤器: 若要自定义一个过滤器,则 ...

  7. 从零开始学Python第0周:Python基本介绍(部分内容来源于网络)

    Python入门介绍 一,Python的基本介绍 (1)概要 Python是一种解释型,面向对象,动态数据类型的高级程序设计语言.常被广泛用于处理系统管理任务和web编程.现如今Python已经成为了 ...

  8. poj-2236-Wireless Network

    Wireless Network Time Limit: 10000MS   Memory Limit: 65536K Total Submissions: 24155   Accepted: 100 ...

  9. NYOJ:题目490 翻译

    题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=490 这题的输入输出格式好像描述的不太清楚,1)可能是所有数据都完成输入,然后再输出(解法 ...

  10. javascript之八——BOM

    8.1 window对象 BOM的核心对象是window--表示浏览器的一个实例.window有双重角色: 是通过javascript访问浏览器窗口的一个接口: 是ECMAScript规定的Globa ...