java多线程顺序打印1--100的实现方案

一、需求场景分析

需求描述:创建三个线程顺序打印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();
            }
        }
    }

实现原理

  1. 通过synchronized保证代码块原子性

  2. 使用wait()让不满足条件的线程等待

  3. 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();
        }
    }

实现原理

  1. ReentrantLock替代内置锁提供更灵活的锁控制

  2. 每个线程绑定独立的Condition等待队列

  3. 通过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. 初始化信号量数组[1,0,0]

  2. 通过acquire()/release()形成信号量传递链

  3. 每个线程需要获取自己的信号量才能执行

方案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);
        }
    }

实现原理

  1. AtomicInteger保证计数器的原子性

  2. volatile保证标记为flag的可见性

  3. 通过ThreadUtil.sleep()降低CPU空转消耗

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值