如何实现Java多线程交替打印20次数据?
使用synchronized+共享信号量
解题思路,synchronized拿到锁,检查线程是否要执行业务代码,如果是,打印,并更改共享信号量,如果不是,wait交出锁。
注意:在执行完业务代码后需要唤醒线程,由于我们是根据共享变量来决定执行线程的,所以需要唤醒全部的线程,这里使用notifyAll,而非notify,有很多新手在写代码时会遇到多线程卡死的问题,具体表现是没有线程执行代码,但是程序不结束,这就有可能是没有唤醒所有线程,使得线程全部在阻塞队列。
public class Solution{public static volatile int idx;public static Object obj;public static void main(String[] args) {idx = 0;obj = new Object();Runnable runnable = new Runnable() {@Overridepublic void run() {while (idx < 20) {synchronized (obj) {String s = Thread.currentThread().getName();if ((s.equals("A") && idx % 3 == 0) || (s.equals("B") && idx % 3 == 1) || (s.equals("C") && idx % 3 == 2)) {System.out.println(s + idx);idx++;// 这里使用notify可能会唤醒错误的线程,所以最好全部唤醒,去争夺锁obj.notifyAll();} else {try {obj.wait();} catch (Exception e) {e.printStackTrace();}}}}}};new Thread(runnable, "A").start();new Thread(runnable, "B").start();new Thread(runnable, "C").start();}
}
使用ReentrantLock+Condition
使用流程:加锁,判断当前条件是否要await,如果不是,就执行业务代码,并让约定顺序的下一个Condition执行。
唯一缺点是判断是否要await时不够优雅,这一点还要再看看。
public class ByteDance0705 {private static volatile int idx = 0;private static ReentrantLock lock = new ReentrantLock();private static Condition conditionA = lock.newCondition();private static Condition conditionB = lock.newCondition();private static Condition conditionC = lock.newCondition();public static void main(String[] args) {new Thread(new Runnable() {@Overridepublic void run() {for (int i=0;i<20;i+=3) {print("A", conditionA, conditionB);}}}).start();new Thread(new Runnable() {@Overridepublic void run() {for (int i=1;i<20;i+=3) {print("B", conditionB, conditionC);}}}).start();new Thread(new Runnable() {@Overridepublic void run() {for (int i=2;i<20;i+=3) {print("C", conditionC, conditionA);}}}).start();}public static void print(String s, Condition cur, Condition next) {try {lock.lock();if (idx < 20) {while ((s.equals("A") && idx % 3 != 0) || (s.equals("B") && idx % 3 != 1) || (s.equals("C") && idx % 3 != 2)) cur.await();System.out.println(s + idx);idx++;next.signal();}} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}
}