线程通信概念:

线程是操作系统中独立的个体,但这些个体如果不经过特殊的处理就不能成为一个整体,线程间的通信就成为整体的必用方式之一。当线程存在通信指挥,系统间的交互性会更强大,在提高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)的更多相关文章

  1. 多线程通信(wait/notify)

    线程通信概念:线程是操作系统中独立的个体,但这些个体如果不经过特殊的处理就不能成为一个整体,线程间的通信就成为整体的必用方式之一.当线程存在通信指挥,系统间的交互性会更强大,在提高CPU利用率的同时就 ...

  2. 多线程一共就俩问题:1.线程安全(访问共享数据) 2.线程通信(wait(),notify())

    多线程一共就俩问题:1.线程安全(访问共享数据) 2.线程通信(wait(),notify()) 1.线程安全,无非就是加锁,访问共享资源时,synchronized 2.线程通信,就是控制各个线程之 ...

  3. 母鸡下蛋实例:多线程通信生产者和消费者wait/notify和condition/await/signal条件队列

    简介 多线程通信一直是高频面试考点,有些面试官可能要求现场手写生产者/消费者代码来考察多线程的功底,今天我们以实际生活中母鸡下蛋案例用代码剖析下实现过程.母鸡在鸡窝下蛋了,叫练从鸡窝里把鸡蛋拿出来这个 ...

  4. JAVA多线程通信

    JAVA多线程通信 package com.frank.thread; /** * author:pengyan * date:Jun 16, 2011 * file:ProducerAndCusto ...

  5. 多线程协作wait、notify、notifyAll方法简介理解使用 多线程中篇(十四)

    在锁与监视器中有对wait和notify以及notifyAll进行了简单介绍 所有对象都有一个与之关联的锁与监视器 wait和notify以及notifyAll之所以是Object的方法就是因为任何一 ...

  6. 多线程通信的两种方式? (可重入锁ReentrantLock和Object)

    (一)Java中线程协作的最常见的两种方式: (1)利用Object的wait().notify()和notifyAll()方法及synchronized (2)使用Condition.Reentra ...

  7. 8.并发编程--多线程通信-wait-notify-模拟Queue

    并发编程--多线程通信-wait-notify-模拟Queue 1. BlockingQueue 顾名思义,首先是一个队列,其次支持阻塞的机制:阻塞放入和获取队列中的数据. 如何实现这样一个队列: 要 ...

  8. 7.并发编程--多线程通信-wait-notify

    并发编程--多线程通信-wait-notify 多线程通信:线程通信的目的是为了能够让线程之间相互发送信号; 1. 多线程通信: 线程通信的目的是为了能够让线程之间相互发送信号.另外,线程通信还能够使 ...

  9. Android多线程通信机制

    掌握Android的多线程通信机制,我们首先应该掌握Android中进程与线程是什么. 1. 进程 在Android中,一个应用程序就是一个独立的进程(应用运行在一个独立的环境中,可以避免其他应用程序 ...

随机推荐

  1. js 在光标位置插入内容

    原文:https://blog.csdn.net/smartsmile2012/article/details/53642082 createDocumentFragment()用法: https:/ ...

  2. 配置阿里云的金融云上的rsync

    论坛里看到易淘发的教程, 转载过来

  3. flash推流工具<转>

    https://github.com/young-cowboy/young-cowboy.github.io https://www.cnblogs.com/xiaoniuzai/p/7129036. ...

  4. Mysql 死锁分析学习

    https://blog.csdn.net/aesop_wubo/article/details/8286215   * CREATE TABLE `user_item` ( * `id` BIGIN ...

  5. docker之container

    转自:https://www.cnblogs.com/jsonhc/p/7760144.html 运行一个container的本身就是开启一个具有独立namespace的进程 进程有自己的网络,文件系 ...

  6. 尚硅谷redis学习2-redis的安装和HelloWorld

    Reids: remote dictionary server redis特点:支持持久化,支持复杂数据类型,支持备份 下载: 解压: 执行make, make install 可能会需要安装make ...

  7. zookeeper和dubbo的关系

    Dubbo建议使用Zookeeper作为服务的注册中心. 1.   Zookeeper的作用:         zookeeper用来注册服务和进行负载均衡,哪一个服务由哪一个机器来提供必需让调用者知 ...

  8. mysql 设置多个字段聚合自增

    DROP TEMPORARY TABLE IF EXISTS ttp_firstInvest; CREATE TEMPORARY TABLE ttp_firstInvest ( userid varc ...

  9. hmac md5

    import hmac //内置 def simaplemd5(str): m2 = hashlib.md5() m2.update(str) res=m2.hexdigest() return re ...

  10. Android高级控件(下)

    Chronometer计时器 常用的方法 getBase() 基准时间 setFormat 设置显示格式 start() 开始计时 stop() 停止计时 setOnChronometerListen ...