多线程通信(wait和notify)
线程通信概念:
线程是操作系统中独立的个体,但这些个体如果不经过特殊的处理就不能成为一个整体,线程间的通信就成为整体的必用方式之一。当线程存在通信指挥,系统间的交互性会更强大,在提高CPU利用率的同时还会使开发人员对线程任务在处理的过程中进行有效的把控与监督。
使用wait/notify方法实现线程间的通信。(注意这两个方法都是object的类的方法,换句话说java为所有的对象都提供了这两个方法)
1 wait和notify必须配合synchronized关键字使用
2wait方法释放锁,notify方法不释放锁
下面看一段demo:
public class ListAdd1 {
private volatile static List list = new ArrayList();
public void add() {
list.add("bjsxt");
}
public int size() {
return list.size();
}
public static void main(String[] args) {
final ListAdd1 list1 = new ListAdd1();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
list1.add();
System.out.println("当前线程: " + Thread.currentThread().getName()
+ "添加了一个元素。。");
Thread.sleep(500);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
if (list1.size() == 5) {
System.out.println("当前线程收到通知 : " + Thread.currentThread().getName()
+ " list size = 5 线程停止");
throw new RuntimeException();
}
}
}
}, "t2");
t1.start();
t2.start();
}
}
首先看一下运行结果:

在第一个线程运行到list.size()=5的时候,停止t2线程,这种实现方式非常不好,需要t2线程一直去轮询。
可以使用java里面线程通信的方式去实现及重构上面的这种方式。下面我们看另外一个demo:
public class ListAdd2 {
private volatile static List list = new ArrayList();
public void add() {
list.add("bjsxt");
}
public int size() {
return list.size();
}
public static void main(String[] args) {
//实例化出来一个lock
//当使用 wait 和 notify 的时候,一定要配合着synchronized关键字去使用
final Object lock = new Object();
final ListAdd2 list2 = new ListAdd2();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
synchronized (lock) {
for (int i = 0; i < 10; i++) {
list2.add();
System.out.println("当前线程: " + Thread.currentThread().getName()
+ "添加了一个元素。。");
Thread.sleep(500);
if (list2.size() == 5) {
System.out.println("已经发出通知、、");
lock.notify();
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock) {
if (list2.size() != 5) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("当前线程: " + Thread.currentThread().getName()
+ " 收到通知线程停止");
throw new RuntimeException();
}
}
}, "t2");
t2.start();
t1.start();
}
}
先看一下运行的结果:

他是先打印5个结果,然后发出通知,接着又执行5个元素,这个时候t2才接收到通知,说明这种方式是不具备实时性的,
看一下,这个线程是先启动t2的,首先是t2获取锁,然后等t2wait,这个时候,t2线程释放锁,此时,t1线程获得锁,
然后在list2.size()等于5的时候,调用notify方法,notify方法是不释放锁的,所以t2线程获取不到锁,这个时候,只能等待t1线程执行完,t2线程才能获取锁,进行业务处理。这也就是打印结果是这样的原因。
加入t1和t2换个位置的话,会造成t1获得锁,然后t2就不能获得锁,等t1执行完,list.size()直接就等于10了,然后才会运行t2线程。
弊端:一定要等待t1线程结束后,才能执行另外一个等待的线程,不具备实时性。
下面看一个解决这个弊端的demo:
public class ListAdd3 {
private volatile static List list = new ArrayList();
public void add() {
list.add("bjsxt");
}
public int size() {
return list.size();
}
public static void main(String[] args) {
final ListAdd3 list3 = new ListAdd3();
//括号里面是传递的个数
final CountDownLatch countDownLatch = new CountDownLatch(1);
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
list3.add();
System.out.println("当前线程: " + Thread.currentThread().getName()
+ "添加了一个元素。。");
Thread.sleep(500);
if (list3.size() == 5) {
System.out.println("已经发出通知、、");
countDownLatch.countDown();//类似于notify
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
if (list3.size() != 5) {
try {
countDownLatch.await();//类似于wait
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("当前线程: " + Thread.currentThread().getName()
+ " 收到通知线程停止");
throw new RuntimeException();
}
}, "t2");
t2.start();
t1.start();
}
}
看一下运行结果:

这就实现了线程通信间的实时性。括号里面的数字代表着下面的t1线程里面有几个countDown,具体相关的知识点,以后在分析。
多线程通信(wait和notify)的更多相关文章
- 多线程通信(wait/notify)
线程通信概念:线程是操作系统中独立的个体,但这些个体如果不经过特殊的处理就不能成为一个整体,线程间的通信就成为整体的必用方式之一.当线程存在通信指挥,系统间的交互性会更强大,在提高CPU利用率的同时就 ...
- 多线程一共就俩问题:1.线程安全(访问共享数据) 2.线程通信(wait(),notify())
多线程一共就俩问题:1.线程安全(访问共享数据) 2.线程通信(wait(),notify()) 1.线程安全,无非就是加锁,访问共享资源时,synchronized 2.线程通信,就是控制各个线程之 ...
- 母鸡下蛋实例:多线程通信生产者和消费者wait/notify和condition/await/signal条件队列
简介 多线程通信一直是高频面试考点,有些面试官可能要求现场手写生产者/消费者代码来考察多线程的功底,今天我们以实际生活中母鸡下蛋案例用代码剖析下实现过程.母鸡在鸡窝下蛋了,叫练从鸡窝里把鸡蛋拿出来这个 ...
- JAVA多线程通信
JAVA多线程通信 package com.frank.thread; /** * author:pengyan * date:Jun 16, 2011 * file:ProducerAndCusto ...
- 多线程协作wait、notify、notifyAll方法简介理解使用 多线程中篇(十四)
在锁与监视器中有对wait和notify以及notifyAll进行了简单介绍 所有对象都有一个与之关联的锁与监视器 wait和notify以及notifyAll之所以是Object的方法就是因为任何一 ...
- 多线程通信的两种方式? (可重入锁ReentrantLock和Object)
(一)Java中线程协作的最常见的两种方式: (1)利用Object的wait().notify()和notifyAll()方法及synchronized (2)使用Condition.Reentra ...
- 8.并发编程--多线程通信-wait-notify-模拟Queue
并发编程--多线程通信-wait-notify-模拟Queue 1. BlockingQueue 顾名思义,首先是一个队列,其次支持阻塞的机制:阻塞放入和获取队列中的数据. 如何实现这样一个队列: 要 ...
- 7.并发编程--多线程通信-wait-notify
并发编程--多线程通信-wait-notify 多线程通信:线程通信的目的是为了能够让线程之间相互发送信号; 1. 多线程通信: 线程通信的目的是为了能够让线程之间相互发送信号.另外,线程通信还能够使 ...
- Android多线程通信机制
掌握Android的多线程通信机制,我们首先应该掌握Android中进程与线程是什么. 1. 进程 在Android中,一个应用程序就是一个独立的进程(应用运行在一个独立的环境中,可以避免其他应用程序 ...
随机推荐
- 用代码检查Windows程序的位数
方法就是通过读取程序文件的头部来判断,具体代码如下: #include <stdio.h> #include <windows.h> int CrnGetImageFileMa ...
- element el-upload组件获取文件名
组件的连接:http://element-cn.eleme.io/#/zh-CN/component/upload 需求:点x按钮,获取文件名传到后端服务,把文件从服务器删除 分析: 仔细看文档,会发 ...
- vc/vs开发的应用程序添加dump崩溃日志<转>
原贴地址:https://blog.csdn.net/wangkui1331/article/details/78029940 vc/vs开发的应用程序出现崩溃的时候,由于没有任何记录,导致开发人员很 ...
- Servlet基本_Httpリクエスト、レスポンス
1.リクエスト リクエストは.リクエストライン.メッセージヘッダ.改行.メッセージボディで組まれる. 主なリクエストヘッダは. Accept クライアントが利用可能なデータメディアタイプを指定. Ac ...
- suse 奇怪的crash 问题
最近遇到一个suse的crash 问题: 我没有使用 mkswap /dev/磁盘路径 来制作swap分区,我有很多剩余内存,我设置nr_swapfiles为0,可是我还是遇到了关于swap的cras ...
- 关于PHP Notice: A non well formed numeric value encountered, 你知道多少
---------------------------------------------------------------------------------------------- A non ...
- Python读取图片尺寸、图片格式
Python读取图片尺寸.图片格式 需要用到PIL模块,使用pip安装Pillow.Pillow是从PIL fork过来的Python 图片库. from PIL import Image im = ...
- 20.pipe
pipe相当于angular1里面的filter 做一些格式转换啊,或者从一个数组里面选取一个元素等等 只要你愿意可以定义很复杂的内容‘’ 我们先看看 angular2 里面自带的一些pipe 我们去 ...
- C# 根据Excel生成树
需求: 根据Excel生成树,Excel的某些节点为属性节点, 如: 列(桩号.构件编码.测试属性1) 是列(分项工程名称) 的属性,非节点. 列(桩号.构件编码.测试属性1) 以属性的方式存在 导入 ...
- 开始jQuery学习之旅
jQuery写法 //实例写法$('div').css({width:200,backgroundColor:'red'}); 参数规则 // css selector$('.wrapper ul l ...