You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java使用wait()和notify()实现两个线程交替持有共享Ball对象问题

问题原因分析
  • 日志打印逻辑错误:takeBall()方法中刚进入方法就打印「拿到球」的日志,此时还未校验球的占用状态,并未真正获取到球的持有权,会出现日志和实际执行状态不符的问题。
  • 锁竞争优先级问题:Java内置的synchronized锁是非公平锁,刚释放锁的线程再次申请锁时,大概率会比已经被唤醒的等待线程先抢到锁。你当前的逻辑中,线程调用完dropBall()释放锁后会立刻进入下一轮循环申请takeBall(),会频繁抢到锁,导致被notify()唤醒的另一个线程拿到锁时,球已经再次被前一个线程占用,只能继续进入等待状态。
解决方案

可以在Ball类中新增变量记录上一次持有球的线程,校验占用状态时增加判断,禁止同一个线程连续持有球,强制两个线程交替执行,同时调整日志打印位置到真正获取到球之后,修正后的Ball类代码如下:

public class Ball{
    boolean ballInUse = false;
    // 新增字段记录上一次持有球的线程名
    String lastHolder = "";

    public synchronized void takeBall() throws InterruptedException {
        // 等待条件:球被占用 或 上一次持有者是当前线程,就继续等待
        while (ballInUse || lastHolder.equals(Thread.currentThread().getName())){
           wait();
        }
        ballInUse = true;
        lastHolder = Thread.currentThread().getName();
        // 真正拿到球后再打印日志
        System.out.println("Ball taken by -> "+Thread.currentThread().getName());
    }


    public synchronized void dropBall() throws InterruptedException {
        System.out.println("Ball dropped by -> "+Thread.currentThread().getName());
        ballInUse = false;
        notify();
    }
}

逻辑说明

新增lastHolder字段后,就算前一个线程释放锁后再次抢到了takeBall()的锁,也会因为「上一次持有者是自己」的校验不通过,主动进入等待状态,把持有权让给另一个线程,完美实现交替持有的要求。

内容的提问来源于stack exchange,提问作者Iosiv

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 02:24:02