Java双线程交替输出12问题:Semaphore与Mutex实现方案排查
错误排查
原代码的核心问题是创建了两个独立的SemTest实例:线程1操作的是semTest1的信号量,线程2操作的是semTest2的信号量,两者的sem1、sem2完全不共享。线程2尝试获取的是自己实例中初始许可为0的sem2,永远无法获取到许可,因此输出第一个1后就陷入阻塞。
Semaphore正确实现方案
使用同一个实例让两个线程共享同一组信号量,保证线程间的同步交互:
import java.util.concurrent.Semaphore; public class SemaphoreAlternate { // 线程1的许可初始为1,线程2的许可初始为0 private final Semaphore sem1 = new Semaphore(1); private final Semaphore sem2 = new Semaphore(0); public static void main(String[] args) { SemaphoreAlternate instance = new SemaphoreAlternate(); // 线程1:输出1 new Thread(() -> { while (true) { try { sem1.acquire(); System.out.print("1"); sem2.release(); // 释放许可让线程2执行 Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }).start(); // 线程2:输出2 new Thread(() -> { while (true) { try { sem2.acquire(); System.out.print("2"); sem1.release(); // 释放许可让线程1执行 Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }).start(); } }
Mutex实现方案(基于synchronized+wait/notify)
通过synchronized互斥锁保证线程安全,配合wait/notify实现顺序控制:
public class MutexAlternate { private boolean turnToPrint1 = true; // 标记当前是否轮到线程1输出 public static void main(String[] args) { MutexAlternate instance = new MutexAlternate(); // 线程1:输出1 new Thread(() -> { synchronized (instance) { while (true) { try { // 不是自己的轮次则等待 while (!turnToPrint1) { instance.wait(); } System.out.print("1"); turnToPrint1 = false; instance.notify(); // 唤醒线程2 Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } }).start(); // 线程2:输出2 new Thread(() -> { synchronized (instance) { while (true) { try { // 不是自己的轮次则等待 while (turnToPrint1) { instance.wait(); } System.out.print("2"); turnToPrint1 = true; instance.notify(); // 唤醒线程1 Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } }).start(); } }
Mutex实现方案(基于ReentrantLock+Condition)
使用显式锁ReentrantLock配合Condition更灵活地控制线程唤醒:
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; public class ReentrantLockAlternate { private final ReentrantLock lock = new ReentrantLock(); private final Condition condition1 = lock.newCondition(); private final Condition condition2 = lock.newCondition(); private boolean turnToPrint1 = true; public static void main(String[] args) { ReentrantLockAlternate instance = new ReentrantLockAlternate(); // 线程1:输出1 new Thread(() -> { lock.lock(); try { while (true) { while (!turnToPrint1) { condition1.await(); } System.out.print("1"); turnToPrint1 = false; condition2.signal(); // 唤醒线程2 Thread.sleep(1000); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { lock.unlock(); } }).start(); // 线程2:输出2 new Thread(() -> { lock.lock(); try { while (true) { while (turnToPrint1) { condition2.await(); } System.out.print("2"); turnToPrint1 = true; condition1.signal(); // 唤醒线程1 Thread.sleep(1000); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { lock.unlock(); } }).start(); } }
内容的提问来源于stack exchange,提问作者T_MAC_1
相关产品推荐
相关产品推荐

