java notify 用法_Java 异步编程之:notify 和 wait 用法

最近看帖子,发现一道面试题:

启动两个线程, 一个输出 1,3,5,7…99, 另一个输出 2,4,6,8…100 最后 STDOUT 中按序输出 1,2,3,4,5…100

题目要求用 Java 的 wait + notify 机制来实现,重点考察对于多线程可见性的理解。

wait 和 notify 简介

wait 和 notify 均为 Object 的方法:

Object.wait() —— 暂停一个线程

Object.notify() —— 唤醒一个线程

从以上的定义中,我们可以了解到以下事实:

想要使用这两个方法,我们需要先有一个 对象

Object。

在多个线程之间,我们可以通过调用 同一个对象

的 wait()

和 notify()

来实现不同的线程间的可见。

对象控制权(monitor)

在使用 wait 和 notify 之前,我们需要先了解对象的控制权(monitor)。在 Java 中任何一个时刻,对象的控制权只能被一个线程拥有。如何理解控制权呢?请先看下面的简单代码:

public class ThreadTest {

public static void main(String[] args) {

Object object = new Object();

new Thread(new Runnable() {

@Override

public void run() {

try {

object.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}).start();

}

}

直接执行,我们将会得到以下异常:

Exception in thread "Thread-0" java.lang.IllegalMonitorStateException

at java.lang.Object.wait(Native Method)

at java.lang.Object.wait(Object.java:502)

at com.xiangyu.demo.ThreadTest$1.run(ThreadTest.java:10)

at java.lang.Thread.run(Thread.java:748)

出错的代码在: object.wait();

。这里我们需要了解以下事实:

无论是执行对象的 wait、notify 还是 notifyAll 方法,必须保证当前运行的线程取得了该对象的控制权(monitor)

如果在没有控制权的线程里执行对象的以上三种方法,就会报 java.lang.IllegalMonitorStateException 异常。

JVM 基于多线程,默认情况下不能保证运行时线程的时序性

在上面的示例代码中,我们 new 了一个 Thread,但是对象 object 的控制权仍在主线程里。所以会报 java.lang.IllegalMonitorStateException 。

我们可以通过同步锁来获得对象控制权,例如:synchronized 代码块。对以上的示例代码做改造:

public class ThreadTest {

public static void main(String[] args) {

Object object = new Object();

new Thread(new Runnable() {

@Override

public void run() {

synchronized (object){ // 修改处

try {

object.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}).start();

}

}

再次执行,代码不再报错。

解题

了解了对象控制权之后,我们就可以正常地使用 notify 和 wait 了,下面给出我的解题方法,供参考。

public class ThreadTest {

private final Object flag = new Object();

public static void main(String[] args) {

ThreadTest threadTest = new ThreadTest();

ThreadA threadA = threadTest.new ThreadA();

threadA.start();

ThreadB threadB = threadTest.new ThreadB();

threadB.start();

}

class ThreadA extends Thread {

@Override

public void run() {

synchronized (flag) {

for (int i = 0; i <= 100; i += 2) {

flag.notify();

System.out.println(i);

try {

flag.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

}

class ThreadB extends Thread {

@Override

public void run() {

synchronized (flag) {

for (int i = 1; i < 100; i += 2) {

flag.notify();

System.out.println(i);

try {

flag.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值