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()的返回值进行排序。
Java 线程通信的更多相关文章
- 第23章 java线程通信——生产者/消费者模型案例
第23章 java线程通信--生产者/消费者模型案例 1.案例: package com.rocco; /** * 生产者消费者问题,涉及到几个类 * 第一,这个问题本身就是一个类,即主类 * 第二, ...
- Java线程通信
Java线程通信 螣蛇乘雾,终为土灰. 多个线程协同工作完成某个任务时就会涉及到线程间通信问题.如何使各个线程之间同时执行,顺序执行.交叉执行等. 一.线程同时执行 创建两个线程a和b,两个线程内调用 ...
- java线程通信与协作小结 多线程中篇(十六)
在锁与监视器中我们对Object中的方法进行了简单介绍 以监视器原理为核心,三个方法:wait,notify.notifyAll,可以完成线程之间的通信 当然,不会像“语言”似的,有多种多样的沟通 ...
- Java线程通信-生产者消费者问题
线程通信示例——生产者消费者问题 这类问题描述了一种情况,假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者将仓库中的产品取走消费.假设仓库中没有产品,则生产者可以将 产品放入仓库,有 ...
- Java线程通信——wait() 和 notify()
Object类中有关线程通信的方法有两个notify方法和三个wait方法,官方解释: void notify() Wakes up a single thread that is waiting o ...
- JAVA线程通信之生产者与消费者
package cn.test.hf.test3; import java.util.concurrent.locks.Condition;import java.util.concurrent.lo ...
- Java线程入门第二篇
Java线程通信方法 0.(why)每个线程都有自己的栈空间,我们要线程之间进行交流,合作共赢. 1.synchronized和volatile关键字 a) 看下面的synchronized关键字 ...
- java多线程-线程通信
线程通信的目标是使线程间能够互相发送信号.另一方面,线程通信使线程能够等待其他线程的信号. 通过共享对象通信 忙等待 wait(),notify()和 notifyAll() 丢失的信号 假唤醒 多线 ...
- Java核心知识点学习----使用Condition控制线程通信
一.需求 实现线程间的通信,主线程循环3次后,子线程2循环2次,子线程3循环3次,然后主线程接着循环3次,如此循环3次. 即:A->B->C---A->B->C---A-> ...
随机推荐
- JQuery01
一:JQuery 1 JQuery知识 *:就是让我们学会调用JQ插件,其实内部就是对JS的封装. *:jquery里面有三个文件, 第2个和第3个其实里面的内容是一样的,只是第三个对其进行了压缩,使 ...
- 两个dropDownList和一个GridView的选择与显示
很久没有写ASP.NET了,今天有看到论坛上一个问题:"两个dropDownList和一个GridView,已经进行了数据绑定,现在想让第一个下拉菜单的数据改变时,第二个下拉菜单自动变到相应 ...
- 损失函数(Loss Function) -1
http://www.ics.uci.edu/~dramanan/teaching/ics273a_winter08/lectures/lecture14.pdf Loss Function 损失函数 ...
- Hack语言特性之类型化
Hack最基础的特性就是类型标注.PHP5已经开始支持对象的类型化,PHP7也提供了标量类型化声明.Hack提供了全面的类型标注支持,与其typecher配合使用,还可以实现快速.前置静态类型验证. ...
- FNV哈希算法
由来:FNV哈希算法全名为Fowler-Noll-Vo算法,是以三位发明人Glenn Fowler,Landon Curt Noll,Phong Vo的名字来命名的,最早在1991年提出. 特点和用途 ...
- JQuery的调用
在head标签中引用一个JQuery的文件用以制作鼠标点击动画,(JQuery包可从网上下载) JS包,脚本语言 <script language="javascript" ...
- html中代码高亮显示
<html> <head> <meta http-equiv=”Content-Type” content=”text/html; charset=UTF-8″> ...
- Scalaz(6)- typeclass:Functor-just map
Functor是范畴学(Category theory)里的概念.不过无须担心,我们在scala FP编程里并不需要先掌握范畴学知识的.在scalaz里,Functor就是一个普通的typeclass ...
- Swagger接入
一 简介 Swagger是一个开源项目,用于描述和生成RestAPi的文档.可以帮助开发人员快速了解web服务的功能. 二 接入Swagger流程 1.在所在Module的pom.xml中,添加Sw ...
- Hibernate(三)__核心接口和类
该图显示了核心接口类以及配置文件的关系层次,越往下越偏向底层数据库. 1. hibernate.cfg.xml文件 ①该文件主要用于指定各个参数,是hibernate核心文件 ②默认放在src目录下, ...