在本文中,我们将带你了解使用Thread的wait和notify方法实现线程通信在这篇文章中,我们将为您详细介绍使用Thread的wait和notify方法实现线程通信的方方面面,并解答threadw
在本文中,我们将带你了解使用Thread的wait和notify方法实现线程通信在这篇文章中,我们将为您详细介绍使用Thread的wait和notify方法实现线程通信的方方面面,并解答thread wait notify常见的疑惑,同时我们还将给您一些技巧,以帮助您实现更有效的19 使用wait和notify/notifyall 实现生产者消费者、Java Thread wait、notify与notifyAll、Java 同步方式 (2) —— wait和notify/notifyall、Java 线程通信之 wait/notify 机制。
本文目录一览:- 使用Thread的wait和notify方法实现线程通信(thread wait notify)
- 19 使用wait和notify/notifyall 实现生产者消费者
- Java Thread wait、notify与notifyAll
- Java 同步方式 (2) —— wait和notify/notifyall
- Java 线程通信之 wait/notify 机制
使用Thread的wait和notify方法实现线程通信(thread wait notify)
package thread1;
/**
* 线程通信例子(基于线程wait,notify)
* */
public class PC {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Q q = new Q();
new Producer(q);
new Customer(q);
//System.out.println("Press Control-C to stop.");
}
}
/**
* 阻塞队列
* */
class Q{
int n;
boolean valueSet = false;
@SuppressWarnings("static-access")
synchronized int get(){
//值未设置好,循环等待
while(!valueSet){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//取值成功
System.out.println("Got:"+n);
//将设置标志置为false
valueSet = false;
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//通知设值线程
this.notify();
return n;
}
@SuppressWarnings("static-access")
synchronized void put(int n){
//已经设置好了值,而且未被取走,循环等待
while(valueSet){
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.n = n;
//将设置标志设置为true
valueSet = true;
System.out.println("Put:"+n);
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//通知取值线程,可以取值
this.notify();
}
}
/**
* 生产者
* */
class Producer implements Runnable{
Q q;
public Producer(Q q){
this.q = q;
new Thread(this,"Producer").start();
}
@Override
public void run() {
// TODO Auto-generated method stub
int i=0;
while(true){
q.put(i++);
}
}
}
/**
* 消费者
* */
class Customer implements Runnable{
Q q;
public Customer(Q q){
this.q=q;
new Thread(this,"Customer").start();
}
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
q.get();
}
}
}
19 使用wait和notify/notifyall 实现生产者消费者
写一个固定容量同步容器,拥有put和get方法,以及getCount方法, 能够支持2个生产者线程以及10个消费者线程的阻塞调用 (使用wait和notify/notifyAll来实现)
注意:为什么用while,不用if (《effective java》中说到:wait都是配合while使用) wait/notify都是和while配合应用的。可以避免多线程并发判断逻辑失效问题。
if只会判断一次,而while一直会判断
永远要使用notifyAll不要使用notify。
public class MyContainer1<T> {
final private LinkedList<T> lists = new LinkedList<>();
final private int MAX = 10; //最多10个元素
private int count = 0; //当前有多少个
public synchronized void put(T t) {
while(lists.size() == MAX) { //想想为什么用while而不是用if?
try {
this.wait(); //effective java
} catch (InterruptedException e) {
e.printStackTrace();
}
}
lists.add(t);
++count;
this.notifyAll(); //通知消费者线程进行消费
}
public synchronized T get() {
T t = null;
while(lists.size() == 0) {
try {
this.wait(); //effective java
} catch (InterruptedException e) {
e.printStackTrace();
}
}
t = lists.removeFirst();
count --;
this.notifyAll(); //通知生产者进行生产
return t;
}
public static void main(String[] args) {
MyContainer1<String> c = new MyContainer1<>();
//启动消费者线程
for(int i=0; i<10; i++) {
new Thread(()->{
for(int j=0; j<5; j++) System.out.println(c.get());
}, "c" + i).start();
}
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
//启动生产者线程
for(int i=0; i<2; i++) {
new Thread(()->{
for(int j=0; j<25; j++) c.put(Thread.currentThread().getName() + " " + j);
}, "p" + i).start();
}
}
}
Java Thread wait、notify与notifyAll
Java的Object类包含了三个final方法,允许线程就资源的锁定状态进行通信。这三个方法分别是:wait(),notify(),notifyAll(),今天来了解一下这三个方法。在任何对象上调用这些方法的当前线程应具有对象监视器(锁住了一个对象,就是获得对象相关联的监视器),否则会抛出java.lang.IllegalMonitorStateException异常。
wait
Object.wait有三种重载的实现,一个无限期等待任何其他线程地调用对象的notify或notifyAll方法来唤醒当前线程。 其他两个会使当前线程在等待特定的时间后进行唤醒。
wait()
使得当前线程进程等待,直到另一个线程在这个对象上调用了notify()方法或者notifyAll()方法。这个方法的行为,完全等价于调用wait(0),可以看它的实现代码为:
public final void wait() throws InterruptedException {
wait(0);
}
当前的线程必须获得这个对象的监视器。线程释放了监视器的所有权,直到另一个线程调用notify方法或者notifyAll方法,去唤醒在这个对象监视器上等待的其他线程。释放了监视器的所有权后,线程便进行等待,直到重新获得监视器的所有权并恢复执行。处于wait状态中的线程,可能被中断或虚假唤醒,所以这个方法应该总是在一个循环中使用:
synchronized (obj) {
while (<condition does not hold>)
obj.wait();
... // Perform action appropriate to condition
}
虚假唤醒指的是一些obj.wait()会在除了obj.notify()和obj.notifyAll()的其他情况被唤醒,而此时是不应该唤醒的,更详细的可以看Spurious_wakeup。
方法会抛出两种异常:
IllegalMonitorStateException:如果当前线程没有获得当前对象的监视器。
InterruptedException:如果某个线程在当前线程等待通知的时候,或是在等待通知之前中断了当前线程,当抛出这个异常时,当前线程的中断状态被清除。
wait(long timeout)
该方法会使得当前进程进入wait状态直到另一个线程调用notify/notifyAll,或是经过了指定的时间,线程将被唤醒。该方法会抛出异常:
IllegalArgumentException:如果timeout是负数。
wait(long timeout, int nanos)
同样的,该方法会使得当前进程进入wait状态直到另一个线程调用notify/notifyAll。它可以更加精细地控制等待的时间,以纳秒为单位测量的实时量由下式给出:1000000*timeout+nanos。除此之外,这个方法与wait(long)做相同的事情,特别的,wait(0,0)等价于wait(0)。除了其余两个wait方法会抛出的异常外,这个方法会抛出异常:
IllegalArgumentException:如果timeout是负数,或者nanos的范围不在0-999999之间时,抛出该异常。
notify
notify方法只唤醒等待对象的一个线程,并且该线程开始执行。所以如果有多个线程在等待一个对象,这个方法只会唤醒其中的一个。线程的选择取决于线程管理的OS实现。
notifyAll
notifyAll方法唤醒等待对象的所有线程,但哪一个将首先处理取决于操作系统的实现。
这些方法可用于实现生产者消费者问题,其中消费者线程正在等待队列中的对象,生产者线程将对象放入队列中并通知等待的线程。下面是一个多个线程工作在同一个对象上的例子,使用了wait,notify,notifyAll方法:
一个例子
Message :被通知唤醒的对象
public class Message {
private String msg;
public Message(String str){
this.msg=str;
}
public String getMsg() {
return msg;
}
public void setMsg(String str) {
this.msg=str;
}
}
Notifier:执行唤醒操作
public class Notifier implements Runnable {
private Message msg;
public Notifier(Message msg) {
this.msg = msg;
}
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(name+" started");
try {
Thread.sleep(1000);
synchronized (msg) {
msg.setMsg(name+" Notifier work done");
msg.notify();
// msg.notifyAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Waiter: 使Message 对象进行wait状态
public class Waiter implements Runnable{
private Message msg;
public Waiter(Message m){
this.msg=m;
}
@Override
public void run() {
String name = Thread.currentThread().getName();
synchronized (msg) {
try{
System.out.println(name+" waiting to get notified at time:"+System.currentTimeMillis());
msg.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(name+" waiter thread got notified at time:"+System.currentTimeMillis());
//process the message now
System.out.println(name+" processed: "+msg.getMsg());
}
}
}
WaitNotifyTest:测试
public class WaitNotifyTest {
public static void main(String[] args) {
Message msg = new Message("process it");
Waiter waiter = new Waiter(msg);
new Thread(waiter,"waiter").start();
Waiter waiter1 = new Waiter(msg);
new Thread(waiter1, "waiter1").start();
Notifier notifier = new Notifier(msg);
new Thread(notifier, "notifier").start();
System.out.println("All the threads are started");
}
}
输出:
waiter waiting to get notified at time:1516757290631
All the threads are started
waiter1 waiting to get notified at time:1516757290632
notifier started
waiter waiter thread got notified at time:1516757291632
waiter processed: notifier Notifier work done
可以看到两个线程在对象msg上进行等待,调用notify方法时,只有一个线程被唤醒,此时程序并没有退出,因为还有一个线程在等待。
如果把notify方法改成notifyAll,运行结果为:
waiter waiting to get notified at time:1516757437164
waiter1 waiting to get notified at time:1516757437164
All the threads are started
notifier started
waiter1 waiter thread got notified at time:1516757438165
waiter1 processed: notifier Notifier work done
waiter waiter thread got notified at time:1516757438165
waiter processed: notifier Notifier work done
可以看到两个线程都被唤醒了,程序也退出运行了。
(完)
Java 同步方式 (2) —— wait和notify/notifyall
Java 中除了关键字 synchronized 能够实现线程同步外,还可以使用 wait 和 notify/notify 实现同步。
wait 方法是使拥有当前对象(object)的线程(thread)放弃锁(release lock),进入睡眠状态
notify 通知 该对象(object)因上面 调用 wait而等待的某一进程重新唤醒启动notifyAll 通知在对象(object)上因调用wait而等待的所有进程启动,这些进程根据优先级顺序执行
一个线程在其生命周期内总是处于某种状态:
- 创建: 当一个线程对象被声明并创建后,它处于“创建”状态;
- 就绪:线程对象调用 start() 方法后,将进入“就绪”状态,处于“就绪”状态的线程不是立即执行,而是进入就绪队列,等待CPU;
- 运行:当就绪队列中具有最高优先级的就绪线程被调度并获得CPU时,便进入“运行”状态,执行 run() 方法,run 方法中定义了线程的操作和功能;
- 非运行:处于“运行”状态的线程可能因为某些原因 (例如人为挂起)进入“非运行”状态,让出CPU并临时中止自己的执行;
- 停止:线程完成了它的全部工作或调用 stop() 方法强制中止线程,线程就进入“停止”状态。
wait 与 sleep 区别
|
wait |
sleep |
归属类 |
属于Object类(java.lang.Object) |
属于Thread类(java.lang.Thread),静态方法 |
释放锁 |
释放了锁,其它线程同步块或方法 |
没有释放锁,不出让系统资源(如cpu) |
中断唤醒 |
wait一般不会加时间限制,而是判断是否满足符合条件; 如果符合条件,则notify/notifyall唤醒 |
sleep(milliseconds)后自动唤醒, 如果时间不到可用interrupt()强制中断 |
适用范围 |
同步方法或同步块使用(synchronized) |
任何地方都可使用(main、thread线程) |
捕获异常 |
必须捕获异常(try/catch) |
不需要捕获异常 |
wait - sleep 示例(区别)
package com.homer.thread; public class waitsleep { public static void main(String[] args) { ThreadDemo th = new ThreadDemo(); th.start(); System.out.println("thread is starting..."); synchronized (th) { try { System.out.println("Waiting for th to complete..."); // th.wait(1000); // 等待1秒后,立刻执行 th.wait(); // 线程等待,notify唤醒后执行 } catch (Exception e) { e.printStackTrace(); } System.out.println("Total is : " + th.total); // 线程唤醒后,执行 } } } class ThreadDemo extends Thread { int total; @Override public void run(){ try { Thread.sleep(2000); // 睡眠2秒 synchronized(this){ System.out.println("Thread is running..."); for(int i=0; i<10; i++) { total += i; System.out.println("i = " + i + "; total = " + total); if(i==5) { System.out.println("i = 5 sleep(3000)"); Thread.sleep(3000); // i = 5时,睡眠3秒 } } this.notify(); } } catch (Exception e) { e.printStackTrace(); } } }运行结果:
thread is starting...
Waiting for th to complete...
Thread is running...
i = 0; total = 0
i = 1; total = 1
i = 2; total = 3
i = 3; total = 6
i = 4; total = 10
i = 5; total = 15
i = 5 sleep(3000)
i = 6; total = 21
i = 7; total = 28
i = 8; total = 36
i = 9; total = 45
Total is : 45
================================
wait - notify 示例(生产者 - 消费者)
package com.homer.thread; public class waitnotify { public static void main(String[] args) { Q q = new Q(); new Producer(q); new Consumer(q); } } class Producer implements Runnable { Q q = null; public Producer(Q q) { this.q = q; (new Thread(this, "Producer")).start(); } @Override public void run() { int i = 0; while(i<5) { q.put(i++); } } } class Consumer implements Runnable { Q q = null; public Consumer(Q q) { this.q = q; (new Thread(this, "Consumer")).start(); } @Override public void run() { while(q.get()<5){ } } } class Q { int n; boolean valueSet = false; public synchronized int get() { if(!valueSet) { // if valueSet == false,wait else try to got value try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("Get n : " + n); valueSet = false; notify(); return n; } public synchronized void put(int n) { if(valueSet) { // if valueSet == true,already have value so wait fetch,else put try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } this.n = n; System.out.println("Put n : " + n); valueSet = true; notify(); } }运行结果:
Put n : 0
Get n : 0
Put n : 1
Get n : 1
Put n : 2
Get n : 2
Put n : 3
Get n : 3
Put n : 4
Get n : 4
首先两个线程启动,他们的执行占用CPU多少随机,但是这里因为加了一个锁的Boolean型变量,而控制了put与set.
首先:创建了一个对象Q,创建了一个Producer,一个Consumer,这两个对象在构造方法中启动了线程.
第一步:
对于Producer来说,会首先去调用put方法,因为valueSet是默认值是false,所以在Q的put方法不执行wait 而是执行 this.n = n 赋值操作,执行完毕后设置为valueSet = true
对于Consumer来说,会首先去调用get方法,因为valueSet是默认值是false,所以该线程会执行wait(等待valueSet 赋值状态为true)
第二步:
对于Producer来说,因为valueSet已经变成true,所以会wat.
对于Consumer来说,因为valueSet已经变成true,所以会执行下面的code(get value),然后设置valueSet为false.
第三步:
Producer执行put方法,因为valueSet为false
Consumer等待(重复第一步)
依次类推,方法执行...
这里关键是加了一个共享的变量 valueSet 来判是该取值get,还是put值。当然有了wait跟notify才使它成为了可以实现的。
但是不管怎样,wait是使目前控制该对象(Q的对象q)的线程wait(等待),notify是使前面在该对象上面wait的方法继续执行.
示例代码下载
原文链接: http://blog.csdn.net/sunboy_2050/article/details/7685594
Java 线程通信之 wait/notify 机制
前言
Java 线程通信是将多个独立的线程个体进行关联处理,使得线程与线程之间能进行相互通信。比如线程 A 修改了对象的值,然后通知给线程 B,使线程 B 能够知道线程 A 修改的值,这就是线程通信。
wait/notify 机制
一个线程调用 Object 的 wait() 方法,使其线程被阻塞;另一线程调用 Object 的 notify()/notifyAll() 方法,wait() 阻塞的线程继续执行。
wai/notify 方法
方法 | 说明 |
---|---|
wait() | 当前线程被阻塞,线程进入 WAITING 状态 |
wait(long) | 设置线程阻塞时长,线程会进入 TIMED_WAITING 状态。如果设置时间内(毫秒)没有通知,则超时返回 |
wait(long, int) | 纳秒级别的线程阻塞时长设置 |
notify() | 通知同一个对象上已执行 wait() 方法且获得对象锁的等待线程 |
notifyAll() | 通知同一对象上所有等待的线程 |
实现 wait/notify 机制的条件:
- 调用 wait 线程和 notify 线程必须拥有相同对象锁。
- wait() 方法和 notify()/notifyAll() 方法必须在 Synchronized 方法或代码块中。
由于 wait/notify 方法是定义在java.lang.Object
中,所以在任何 Java 对象上都可以使用。
wait 方法
在执行 wait() 方法前,当前线程必须已获得对象锁。调用它时会阻塞当前线程,进入等待状态,在当前 wait() 处暂停线程。同时,wait() 方法执行后,会立即释放获得的对象锁。
下面通过案例来查看 wait() 释放锁。
首先查看不使用 wait() 方法时的代码执行情况:
package top.ytao.demo.thread.waitnotify;
/**
* Created by YangTao
*/
public class WaitTest {
static Object object = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (object){
System.out.println("开始线程 A");
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("结束线程 A");
}
}, "线程 A").start();
new Thread(() -> {
try {
Thread.sleep(500L);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (object){
System.out.println("开始线程 B");
System.out.println("结束线程 B");
}
}, "线程 B").start();
}
}
创建 A、B 两个线程,。首先在 B 线程创建后 sleep ,保证 B 线程的打印后于 A 线程执行。在 A 线程中,获取到对象锁后,sleep 一段时间,且时间大于 B 线程的 sleep 时间。
执行结果为:
从上图结果中,可以看到,B 线程一定等 A 线程执行完 synchronize 代码块释放对象锁后 A 线程再获取对象锁进入 synchronize 代码块中。在这过程中,Thread.sleep() 方法也不会释放锁。
当前在 A 线程 synchronize 代码块中执行 wait() 方法后,就会主动释放对象锁,A 线程代码如下:
new Thread(() -> {
synchronized (object){
System.out.println("开始线程 A");
try {
// 调用 object 对象的 wait 方法
object.wait();
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("结束线程 A");
}
}, "线程 A").start();
执行结果:
同时 A 线程一直处于阻塞状态,不会打印结束线程 A
。
wait(long) 方法是设置超时时间,当等待时间大于设置的超时时间后,会继续往 wait(long) 方法后的代码执行。
new Thread(() -> {
synchronized (object){
System.out.println("开始线程 A");
try {
object.wait(1000);
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("结束线程 A");
}
}, "线程 A").start();
执行结果
同理,wait(long, int) 方法与 wait(long) 同样,只是多个纳秒级别的时间设置。
notify 方法
同样,在执行 notify() 方法前,当前线程也必须已获得线程锁。调用 notify() 方法后,会通知一个执行了 wait() 方法的阻塞等待线程,使该等待线程重新获取到对象锁,然后继续执行 wait() 后面的代码。但是,与 wait() 方法不同,执行 notify() 后,不会立即释放对象锁,而需要执行完 synchronize 的代码块或方法才会释放锁,所以接收通知的线程也不会立即获得锁,也需要等待执行 notify() 方法的线程释放锁后再获取锁。
notify()
下面是 notify() 方法的使用,实现一个完整的 wait/notify 的例子,同时验证发出通知后,执行 notify() 方法的线程是否立即释放锁,执行 wait() 方法的线程是否立即获取锁。
package top.ytao.demo.thread.waitnotify;
/**
* Created by YangTao
*/
public class WaitNotifyTest {
static Object object = new Object();
public static void main(String[] args) {
System.out.println();
new Thread(() -> {
synchronized (object){
System.out.println("开始线程 A");
try {
object.wait();
System.out.println("A 线程重新获取到锁,继续进行");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("结束线程 A");
}
}, "线程 A").start();
new Thread(() -> {
try {
Thread.sleep(500L);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (object){
System.out.println("开始线程 B");
object.notify();
System.out.println("线程 B 通知完线程 A");
try {
// 试验执行完 notify() 方法后,A 线程是否能立即获取到锁
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("结束线程 B");
}
}, "线程 B").start();
}
}
以上 A 线程执行 wait() 方法,B 线程执行 notify() 方法,执行结果为:
执行结果中可以看到,B 线程执行 notify() 方法后,即使 sleep 了,A 线程也没有获取到锁,可知,notify() 方法并没有释放锁。
notify() 是通知到等待中的线程,但是调用一次 notify() 方法,只能通知到一个执行 wait() 方法的等待线程。如果有多个等待状态的线程,则需多次调用 notify() 方法,通知到线程顺序则根据执行 wait() 方法的先后顺序进行通知。
下面创建有两个执行 wait() 方法的线程的代码:
package top.ytao.demo.thread.waitnotify;
/**
* Created by YangTao
*/
public class MultiWaitNotifyTest {
static Object object = new Object();
public static void main(String[] args) {
System.out.println();
new Thread(() -> {
synchronized (object){
System.out.println("开始线程 A");
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("结束线程 A");
}
}, "线程 A").start();
new Thread(() -> {
try {
Thread.sleep(500L);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (object){
System.out.println("开始线程 B");
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("结束线程 B");
}
}, "线程 B").start();
new Thread(() -> {
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (object){
System.out.println("开始通知线程 C");
object.notify();
object.notify();
System.out.println("结束通知线程 C");
}
}, "线程 C").start();
}
}
先 A 线程执行 wait() 方法,然后 B 线程执行 wait() 方法,最后 C 线程调用两次 notify() 方法,执行结果:
notifyAll()
通知多个等待状态的线程,通过多次调用 notify() 方法实现的方案,在实际应用过程中,实现过程不太友好,如果是想通知所有等待状态的线程,可使用 notifyAll() 方法,就能唤醒所有线程。
实现方式,只需将上面 C 线程的多次调用 notify() 方法部分改为调用一次 notifyAll() 方法即可。
new Thread(() -> {
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (object){
System.out.println("开始通知线程 C");
object.notifyAll();
System.out.println("结束通知线程 C");
}
}, "线程 C").start();
执行结果:
根据不同 JVM 的实现,notifyAll() 的唤醒顺序会有所不同,当前测试环境中,以倒序顺序唤醒线程。
实现生产者消费者模式
生产消费者模式就是一个线程生产数据进行存储,另一线程进行数据提取消费。下面就以两个线程来模拟,生产者生成一个 UUID 存放到 List 对象中,消费者读取 List 对象中的数据,读取完成后进行清除。
实现代码如下:
package top.ytao.demo.thread.waitnotify;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
* Created by YangTao
*/
public class WaitNotifyModelTest {
// 存储生产者产生的数据
static List<String> list = new ArrayList<>();
public static void main(String[] args) {
new Thread(() -> {
while (true){
synchronized (list){
// 判断 list 中是否有数据,如果有数据的话,就进入等待状态,等数据消费完
if (list.size() != 0){
try {
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// list 中没有数据时,产生数据添加到 list 中
list.add(UUID.randomUUID().toString());
list.notify();
System.out.println(Thread.currentThread().getName() + list);
}
}
}, "生产者线程 A ").start();
new Thread(() -> {
while (true){
synchronized (list){
// 如果 list 中没有数据,则进入等待状态,等收到有数据通知后再继续运行
if (list.size() == 0){
try {
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 有数据时,读取数据
System.out.println(Thread.currentThread().getName() + list);
list.notify();
// 读取完毕,将当前这条 UUID 数据进行清除
list.clear();
}
}
}, "消费者线程 B ").start();
}
}
运行结果:
生产者线程运行时,如果已存在未消费的数据,则当前线程进入等待状态,收到通知后,表明数据已消费完,再继续向 list 中添加数据。
消费者线程运行时,如果不存在未消费的数据,则当前线程进入等待状态,收到通知后,表明 List 中已有新数据被添加,继续执行代码消费数据并清除。
不管是生产者还是消费者,基于对象锁,一次只能一个线程能获取到,如果生产者获取到锁就校验是否需要生成数据,如果消费者获取到锁就校验是否有数据可消费。
一个简单的生产者消费者模式就以完成。
总结
等待/通知机制是实现 Java 线程间通信的一种方式,将多线程中,各个独立运行的线程通过相互通信来更高效的协作完成工作,更大效率利用 CPU 处理程序。这也是学习或研究 Java 线程的必学知识点。
推荐阅读
《Java 线程基础,从这篇开始》
《你必须会的 JDK 动态代理和 CGLIB 动态代理》
《Dubbo 系列》
关注公众号 『ytao』 坚持原创技术文章输出,专注但不限于 Java 相关技术。
关于使用Thread的wait和notify方法实现线程通信和thread wait notify的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于19 使用wait和notify/notifyall 实现生产者消费者、Java Thread wait、notify与notifyAll、Java 同步方式 (2) —— wait和notify/notifyall、Java 线程通信之 wait/notify 机制的相关信息,请在本站寻找。
本文标签: