线程通信概念:

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

    具体可参考:http://www.liujiangblog.com/course/django/153 https://www.cnblogs.com/liuguniang/p/7141837.htm ...

  2. python字符串的基本用法

    var1 = "hello word"var2 = "runootab"print var2.capitalize()#首字母大写print (var2.cou ...

  3. 学习别人的rpc框架

    https://my.oschina.net/huangyong/blog/361751 https://gitee.com/huangyong/rpc 在此文基础上的另一个实现,解决了原文中一些问题 ...

  4. Object-c @property与@synthesize的配对使用。

    功能:让编译器自动编写一个与数据成员同名的方法声明来省去读写方法的声明. 如: 1.在头文件中: @property int count; 等效于在头文件中声明2个方法: - (int)count; ...

  5. LeetCode OJ 2. Add Two Numbers

    You are given two non-empty linked lists representing two non-negative integers. The digits are stor ...

  6. Delphi判断是否有全屏程序

    unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms ...

  7. python 装饰器的缺点以及解决方法

    1.python装饰器的缺点 装饰器可以允许我们在不改变函数或犯方法的调用方式的情况下,添加额外的功能; 如下所示,我们要在中的方法之前增加装饰器check_is_admin,用来判断执行类的方法的用 ...

  8. easyUi 表头排序按钮 bug

    参考文章:https://www.shiqidu.com/p/81

  9. Mac中opencv批量对图片进行二值化

    对灰度图像进行二值化,传入的图片是手写汉字的截图,通过二值化把字的部分提出来.用ostu进行二值化 #include <stdio.h> #include <iostream> ...

  10. shiro 基于springmvc中做登陆功能

    1.添加依赖 <!-- shiro --> <dependency> <groupId>org.apache.shiro</groupId> <a ...