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
相关产品推荐
相关产品推荐

