一、需求场景分析
需求描述:创建三个线程顺序打印1--100
二、实现方案
方案1: 使用synchronized + wait + notifyAll实现
static final Object objectLock = new Object();
static Integer count = 1;
public static void main(String[] args) {
new Thread(() -> print1(0), "线程1").start();
new Thread(() -> print1(1), "线程2").start();
new Thread(() -> print1(2), "线程3").start();
}
/**使用synchronized + wait + notifyAll实现*/
private static void print1(int res){
synchronized (objectLock){
while (count<=100){
while (count % 3 != res){
if (count>100) break;
try {
//不满足条件的线程等待
objectLock.wait();
}catch (Exception e){
e.printStackTrace();
}
}
//满足条件的线程打印数字然后唤醒其它线程
if (count>100) break;
System.out.println(Thread.currentThread().getName()+":"+count);
count++;
objectLock.notifyAll();
}
}
}
实现原理
通过synchronized保证代码块原子性
使用wait()让不满足条件的线程等待
notifyAll()唤醒所有线程重新竞争锁
方案2: 使用ReentrantLock+Condition (精准唤醒)
static Integer count = 1;
private static Lock reentrantLock = new ReentrantLock();
private static Condition[] conditions = {reentrantLock.newCondition(), reentrantLock.newCondition(),reentrantLock.newCondition()};
public static void main(String[] args) {
new Thread(() -> print2(0), "线程1").start();
new Thread(() -> print2(1), "线程2").start();
new Thread(() -> print2(2), "线程3").start();
}
/**使用ReentrantLock+Condition (精准唤醒)*/
private static void print2(int res){
//每个线程获取一道锁
reentrantLock.lock();
try {
while (count<=100){
//判断是否满足当前线程打印的条件
while (count%3!=res){
if (count>100) break;
//不满足当前打印条件的线程等待
conditions[res].await();
}
if (count>100) break;
System.out.println(Thread.currentThread().getName()+":"+count);
count++;
//精准唤醒下一个满足条件的线程
conditions[(res+1)%3].signal();
}
//循环结束唤醒所有线程
conditions[res].signalAll();
}catch (Exception e){
e.printStackTrace();
}finally {
reentrantLock.unlock();
}
}
实现原理
ReentrantLock替代内置锁提供更灵活的锁控制
每个线程绑定独立的Condition等待队列
通过signal()实现精准线程唤醒
方案3: 使用Semaphore信号量实现
static Integer count = 1;
private static Semaphore[] semaphores = {new Semaphore(1),new Semaphore(0),new Semaphore(0)};
public static void main(String[] args) {
new Thread(() -> print3(0), "线程1").start();
new Thread(() -> print3(1), "线程2").start();
new Thread(() -> print3(2), "线程3").start();
}
/**使用Semaphore信号量实现*/
private static void print3(int res){
while (count<=100){
try {
//获取一个令牌,信号量减一,若信号量许可数为0则等待
semaphores[res].acquire();
if (count>100) break;
System.out.println(Thread.currentThread().getName()+":"+count);
count++;
//释放一个令牌,信号量加一
semaphores[(res+1)%3].release();
}catch (Exception e){
e.printStackTrace();
}
}
for (Semaphore semaphore : semaphores) {
semaphore.release();
}
}
实现原理
初始化信号量数组[1,0,0]
通过acquire()/release()形成信号量传递链
每个线程需要获取自己的信号量才能执行
方案4: 使用AtomicInteger + volatile (无锁CAS)实现
private static AtomicInteger count1 = new AtomicInteger(1);
public static void main(String[] args) {
new Thread(() -> print4(0), "线程1").start();
new Thread(() -> print4(1), "线程2").start();
new Thread(() -> print4(2), "线程3").start();
}
/**使用AtomicInteger + volatile(无锁CAS)实现*/
private static void print4(int res){
while (count1.get()<=100){
while (flag == res && count1.get()<=100){
System.out.println(Thread.currentThread().getName()+":"+count1.getAndIncrement());
flag = (flag + 1) % 3;
}
//让出cpu 避免cpu空转出现忙等待
ThreadUtil.sleep(1);
}
}
实现原理
AtomicInteger保证计数器的原子性
volatile保证标记为flag的可见性
通过ThreadUtil.sleep()降低CPU空转消耗