如何实现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() {
@Override
public 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() {
@Override
public void run() {
for (int i=0;i<20;i+=3) {
print("A", conditionA, conditionB);
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i=1;i<20;i+=3) {
print("B", conditionB, conditionC);
}
}
}).start();
new Thread(new Runnable() {
@Override
public 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();
}
}
}
使用Semaphore+volatile
创建三个信号量,从A开始,所以A的信号量个数是1,其他都是0,等待被release,每个信号量先acquire一个,然后打印,最后release下一个信号量。
public class Solution{
private static volatile int idx = 0;
private static Semaphore semaphoreA = new Semaphore(1);
private static Semaphore semaphoreB = new Semaphore(0);
private static Semaphore semaphoreC = new Semaphore(0);
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 20; i += 3) {
print("A", semaphoreA, semaphoreB);
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 1; i < 20; i += 3) {
print("B", semaphoreB, semaphoreC);
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 2; i < 20; i += 3) {
print("C", semaphoreC, semaphoreA);
}
}
}).start();
}
public static void print(String s, Semaphore cur, Semaphore next) {
try {
if (idx < 20) {
cur.acquire();
System.out.println(s + idx);
idx++;
next.release();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}