首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【高薪程序员必看】万字长文拆解Java并发编程!(3-2):并发共享问题的解决与分析

【高薪程序员必看】万字长文拆解Java并发编程!(3-2):并发共享问题的解决与分析

作者头像
摘星.
发布2025-05-20 14:22:53
发布2025-05-20 14:22:53
1410
举报
文章被收录于专栏:博客专享博客专享

3.5. wait-notify机制

3.5.1. wait-notify介绍

wait方法和notify方法都是Object类的方法

  • object.wait():让当前获取锁的线程进入waiting状态,并进入waitlist队列
  • object.wait(long n):让当前获取锁的线程进入waiting状态,并进入waitlist队列,等待n秒后自动唤醒
  • object.notify():在waitlist队列中挑一个线程唤醒
  • object.notifyAll():唤醒所有在waitlist队列中的线程

它们都是之间协作的手段,只有拥有对象锁的线程才能调用这些方法,否则会出现IllegalMonitorStateException异常

3.5.2. 原理

wait调用条件:owner线程获取了该对象的锁,但是发现自己条件不满足使用共享资源的条件/竞态条件存在时,会调用wait方法进入waiting状态并进入Monitor对象的waitlist中,释放对象锁

处于waiting状态中的线程可以被notify/notifyAll方法唤醒,唤醒之后不一定马上可以获取锁,仍需进入EntryList竞争锁

3.5.3. wait和sleep的区别
  • 从属层面:sleep是Thread方法,wait是Object方法
  • 使用层面:sleep不需要强制和synchronized使用,wait方法需要和synchronized使用
  • 作用效果:sleep在睡眠时不会释放对象锁,wait在等到时会释放对象锁
3.5.4. join原理

join是使用了保护性暂停模式,并在此基础上扩展了超时等待

  • 使用经历时间和这一轮应该等待的时间来确保等待时间不超过指定的时间
  • 当条件不满足但是又经历一次notify,还是进入while循环,这时等待的时间可能会超过指定时间
代码语言:javascript
复制
public final synchronized void join(long millis)throws InterruptedException {
    //开始时间
    long base = System.currentTimeMillis();
    //经历时间
    long now = 0;
    
    if (millis < 0) {
        //如果指定等待时间等于0则抛出异常
        throw new IllegalArgumentException("timeout value is negative");
    }
	
    if (millis == 0) {
        while (isAlive()) {
            wait(0);
        }
    } else {
        //如果指定等待时间为正数
        while (isAlive()) {
            //求出这一轮循环应该等待的时间
            long delay = millis - now;
            if (delay <= 0) {
                //等待时间小于0直接退出循环
                break;
            }
            //等待这一轮应该等待的时间,防止唤醒后的条件不满足再次等待原有时间导致超时
            wait(delay);
            //求出经历的时间
            now = System.currentTimeMillis() - base;
        }
    }
}

3.6. park-unpark机制

3.6.1. park-unpark介绍

park方法和unpark方法是LockSupport类中的方法

  • LockSupport.park():用于暂停当前的线程
  • LockSupport.unpark(thread):用于恢复某个线程,既可以在park()之前调用也可以在之后调用
3.6.2. park-unpark与wait-notify的区别
  • wait-notify是Object类的方法,必须结合加锁对象使用,park-unpark没有限制
  • notify随机唤醒一个线程,notifyAll唤醒全部线程,park(thread)唤醒指定的线程
  • notify必须用在wait之后,unpark既可以用在park之前,也可以用在park之后
3.6.3. park-unpark原理

每个线程都会关联一个Parker(jvm层面)对象,有一个当前线程许可计数permit

  • LockSupport.park():调用park时,会先检查permit,如果大于0则将permit-1后返回,线程继续执行.如果小于0则线程进入阻塞状态,等待被唤醒或打断
  • LockSupport.unpark(thread):调用unpark时,将permit+1,

3.7. 线程状态转换

以下是线程各个状态之间的转换以及调用的方法

NEW-->RUNNABLE

  • thread.start():thread线程的状态NEW-->RUNNABLE

RUNNABLE<-->WAITING

  • 线程进入synchronized(obj)代码块,获取对象锁之后
    • obj.wait():当前线程的状态RUNNABLE-->WAITING
      • obj.notify() 或 obj.notifyAll() 或 obj.interrupt():
      • 竞争锁成功,当前线程的状态WAITING-->RUNNABLE
      • 竞争锁失败,当前线程的状态WAITING-->BLOCKED
  • thread.join():当前线程中调用线程thread的join方法会在thread线程对象上的监视器等待,当前线程的状态RUNNABLE-->WAITING
    • thread线程运行结束 或 被打断:当前线程的状态WAITING-->RUNNABLE
  • LockSupport.park(): 当前线程的状态RUNNABLE-->WAITING
  • LockSupport.unpark(thread):指定线程的状态WAITING-->RUNNABLE

RUNNABLE<-->TIMED_WAITING

  • 线程进入synchronized(obj)代码块,获取对象锁之后
    • obj.wait(long n):当前线程的状态RUNNABLE-->TIMED_WAITING
      • 当前线程等待n秒 或 被唤醒和打断:
      • 竞争锁成功,当前线程的状态TIMED_WAITING-->RUNNABLE
      • 竞争锁失败,当前线程的状态TIMED_WAITING-->BLOCKED
  • Thread.sleep(long n):当前线程的状态RUNNABLE-->TIMED_WAITING
    • 当前线程等待n秒:竞争锁成功,当前线程的状态TIMED_WAITING-->RUNNABLE
  • LockSupport.parkNanos(long nanos) 或 LockSupport.parkUnitl(long millis):当前线程状态:RUNNABLE-->TIMED_WAITING
    • LockSupport.unpark(thread) 或 被打断 或 等待超时:目标线程状态TIMED_WAITING-->RUNNABLE

RUNNABLE<-->BLOCKED

  • thread线程使用synchronized(obj)获取对象锁竞争失败,thread线程状态RUNNABLE-->BLOCKED
    • 持有锁的线程的同步代码块执行完毕,唤醒阻塞中的线程竞争锁
      • 竞争成功BLOCKED-->RUNNABLE
      • 竞争失败BLOCKED

RUNNABLE<-->TERMINATED

  • 当前线程所有代码运行完毕RUNNABLE-->TERMINATED
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-04-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 3.5. wait-notify机制
    • 3.5.1. wait-notify介绍
    • 3.5.2. 原理
    • 3.5.3. wait和sleep的区别
    • 3.5.4. join原理
  • 3.6. park-unpark机制
    • 3.6.1. park-unpark介绍
    • 3.6.2. park-unpark与wait-notify的区别
    • 3.6.3. park-unpark原理
  • 3.7. 线程状态转换
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档