资讯专栏INFORMATION COLUMN

Java多线程中wait 和 notify 方法理解

Turbo / 3146人阅读

摘要:必须放在中,否则会在时扔出异常。为了控制线程执行的顺序,那么就必须要确定唤醒等待的顺序,所以每一个线程必须同时持有两个对象锁,才能继续执行。一个对象锁是,就是前一个线程所持有的对象锁。

简单介绍

wait()方法是Object类里的方法;当一个线程执行到wait()方法时,它就进入到一个和该对象相关的等待池中,同时失去(释放)了对象的机锁(暂时失去机锁,wait(long timeout)超时时间到后还需要返还对象锁);其他线程可以访问;wait()使用notify或者notifyAlll或者指定睡眠时间来唤醒当前等待池中的线程。wiat()必须放在synchronized block中,否则会在program runtime时扔 出“java.lang.IllegalMonitorStateException”异常。
简单的介绍就到这里,现在我们用一个例子来深入理解一下
package com.example.demo.test.MultithreadingTest;

public class MyThreadPrinter2 implements Runnable {
    private String name;
    private Object prev;
    private Object self;

    private MyThreadPrinter2(String name, Object prev, Object self) {
        this.name = name;
        this.prev = prev;
        this.self = self;
    }

    @Override
    public void run() {
        int count = 10;
        int x=0;
        while (count > 0) {
            synchronized (prev) {
                synchronized (self) {
                    System.out.print(name);
                    count--;
                    x++;
                    self.notify();
                }
                try {
                    prev.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            synchronized (prev){
                System.out.print(x);
            }

        }
    }

    public static void main(String[] args) throws Exception {
        Object a = new Object();
        Object b = new Object();
        Object c = new Object();
        MyThreadPrinter2 pa = new MyThreadPrinter2("A", c, a);
        MyThreadPrinter2 pb = new MyThreadPrinter2("B", a, b);
        MyThreadPrinter2 pc = new MyThreadPrinter2("C", b, c);

        new Thread(pa).start();
        Thread.sleep(100);
        new Thread(pb).start();
        Thread.sleep(100);
        new Thread(pc).start();
        Thread.sleep(100);
    }
}

输出结果:
ABC1A1B1C2A2B2C3A3B3C4A4B4C5A5B5C6A6B6C7A7B7C8A8B8C9A9B9C10

这段代码为三线程间的同步唤醒操作,主要的目的就是ThreadA->ThreadB->ThreadC->ThreadA循环执行三个线程。
为了控制线程执行的顺序,那么就必须要确定唤醒、等待的顺序,所以每一个线程必须同时持有两个对象锁,才能继续执行。一个对象锁是prev,就是前一个线程所持有的对象锁。还有一个就是自身对象锁。主要的思想就是,为了控制执行的顺序,必须要先持有prev锁,也就前一个线程要释放自身对象锁,再去申请自身对象锁,两者兼备时打印,之后首先调用self.notify()释放自身对象锁,唤醒下一个等待线程,再调用prev.wait()释放prev对象锁,终止当前线程,等待循环结束后再次被唤醒。prev.wait()之后,加入了一个对象锁是prev的输出x,用来展示什么时候释放了prev对象锁。
运行上述代码,可以发现先打印出A,再释放A,然后C锁,进入ThreadB,打印出B,再释放B,然后A锁,进入ThreadC,打印出C,再释放C,然后B锁,此时会进入ThreadA,继续执行开始时wait的线程,输出x,打印出A,再释放A,然后C锁......如此循环

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/71618.html

相关文章

  • Java 线程编程之:notify wait 用法

    摘要:和简介和均为的方法暂停一个线程唤醒一个线程从以上的定义中,我们可以了解到以下事实想要使用这两个方法,我们需要先有一个对象。在中任何一个时刻,对象的控制权只能被一个线程拥有。若有多个线程处于此控制权下的状态,只有一个会被唤醒。 最近看帖子,发现一道面试题: 启动两个线程, 一个输出 1,3,5,7…99, 另一个输出 2,4,6,8…100 最后 STDOUT 中按序输出 1,2,3,4...

    eccozhou 评论0 收藏0
  • Object对象你真理解了吗?

    摘要:无论在中出现什么,都可以认为它是对象除了八大基本数据类型。让当前线程等待某个对象的锁,当然应该通过这个对象来操作了。但是要注意的是方法调用后,被唤醒的线程不会立马获得到锁对象。主要的区别在于在释放同时,释放了对象锁的控制。 前言 五一回家又断更了一个放假时间了~~~ 只有光头才能变强 回顾前面: ThreadLocal就是这么简单 多线程三分钟就可以入个门了! 多线程基础必要知识点!...

    anquan 评论0 收藏0
  • Java 并发学习笔记

    摘要:方法可以将当前线程放入等待集合中,并释放当前线程持有的锁。此后,该线程不会接收到的调度,并进入休眠状态。该线程会唤醒,并尝试恢复之前的状态。 并发 最近重新复习了一边并发的知识,发现自己之前对于并发的了解只是皮毛。这里总结以下Java并发需要掌握的点。 使用并发的一个重要原因是提高执行效率。由于I/O等情况阻塞,单个任务并不能充分利用CPU时间。所以在单处理器的机器上也应该使用并发。为...

    DrizzleX 评论0 收藏0
  • Java线程学习(四)等待/通知(wait/notify)机制

    摘要:运行可运行状态的线程获得了时间片,执行程序代码。阻塞的情况分三种一等待阻塞运行的线程执行方法,会把该线程放入等待队列中。死亡线程方法执行结束,或者因异常退出了方法,则该线程结束生命周期。死亡的线程不可再次复生。 系列文章传送门: Java多线程学习(一)Java多线程入门 Java多线程学习(二)synchronized关键字(1) java多线程学习(二)synchronized关键...

    PiscesYE 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<