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

Java多线程计数至10场景下线程互斥等待失效问题排查与解决

问题根本原因

synchronized实现互斥的核心前提是所有参与竞争的线程必须争抢同一个锁对象,你的代码不满足这个条件:

  • 你在Count1by1类的成员位置定义了private Object mutex = new Object();,每次创建Count1by1实例时,都会为这个实例生成一个独立的mutex对象
  • 主方法循环里一共创建了5个Count1by1实例,对应5个完全独立的mutex锁
  • 每个线程执行synchronized (mutex)时,锁的是自己持有的私有锁对象,不存在任何锁竞争,自然所有线程都能直接进入同步块执行计数,不会产生等待。

你注释掉构造方法里的this.mutex= new Object();没有任何作用,因为成员变量的初始化语句会在构造方法执行前自动运行,每个实例还是会有自己的独立锁。

另外补充:这个场景不需要手动调用wait()方法。synchronized的内置锁机制已经自动实现了阻塞等待逻辑:没抢到锁的线程会在同步块入口处阻塞挂起,持有锁的线程退出同步块时会自动释放锁,唤醒等待队列里的线程重新竞争锁,完全符合你要的「同一时间只有一个线程计数,其余线程等待」的需求。wait/notify是用来做条件等待的,不适合这个纯互斥的场景。

修复方案

核心思路是让5个线程共享同一个锁对象,两种常用实现方式选其一即可:

方案1:使用类级别的静态锁

把mutex定义为static静态成员,锁对象归Count1by1类所有,所有实例共享同一个锁,不需要修改主类代码:

public class Count1by1 implements Runnable{
    private int threadnumber;
    // 静态锁属于类,所有Count1by1实例共用这一个锁对象
    private static final Object mutex = new Object();

    public Count1by1(int num) {
        this.threadnumber=num;
    }

    public void count() {
        synchronized (mutex) {
            for (int i = 1; i <= 10; i++) {
                System.out.println("#"+threadnumber + " counts: " + i);
                try {
                    Thread.sleep(500);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
    @Override
    public void run() {
        count();
    }
}

方案2:外部传入共享锁

在主类中创建一个统一的锁对象,通过构造方法传给每个Count1by1实例,锁的控制权更灵活:
修改后的主类代码:

public class Main {
    public static void main(String[] ar) {
        // 提前创建所有线程共用的锁对象
        Object sharedMutex = new Object();
        for (int i = 1; i <= 5; i++) {
            // 把同一个锁传给每个线程实例
            Count1by1 count1by1 = new Count1by1(i, sharedMutex);
            Thread myThread = new Thread(count1by1);
            myThread.start();
        }   
    }
}

修改后的Count1by1代码:

public class Count1by1 implements Runnable{
    private int threadnumber;
    private final Object mutex;

    // 构造方法接收外部传入的共享锁
    public Count1by1(int num, Object mutex) {
        this.threadnumber=num;
        this.mutex = mutex;
    }

    public void count() {
        synchronized (mutex) {
            for (int i = 1; i <= 10; i++) {
                System.out.println("#"+threadnumber + " counts: " + i);
                try {
                    Thread.sleep(500);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
    @Override
    public void run() {
        count();
    }
}

两种方案运行效果完全一致:线程会按抢到锁的顺序依次执行1-10的计数,同一时间只会有一个线程在输出计数内容,其余线程阻塞等待,直到当前持有锁的线程计数完成释放锁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 15:24:26