笔/面试的时候常常遇到的一个问题,就是多个线程进行交替的打印任务:
import java.util.concurrent.locks.ReentrantLock;
public class PrintTask extends Thread {
private String task;
private Integer id;
private static Integer taskId;
private static Integer taskCount;
private ReentrantLock lock;
public PrintTask(String task, Integer id, Integer taskId, Integer taskCount, ReentrantLock lock) {
this.task = task;
this.setName("PrintTask-" + task);
this.id = id;
PrintTask.taskId = taskId;
PrintTask.taskCount = taskCount;
this.lock = lock;
}
@Override
public void run() {
while (true) {
lock.lock();
if (taskId % PrintTask.taskCount == id) {
System.out.println(task);
taskId = taskId == PrintTask.taskCount - 1 ? 0 : taskId + 1;
}
lock.unlock();
}
}
public static void main(String[] args) {
String[] tasks = new String[]{"A", "B", "C"};
//使用公平锁,当前线程打印完之后下一次不会马上又轮到自己去获取锁
ReentrantLock lock = new ReentrantLock(true);
PrintTask[] printTasks = new PrintTask[tasks.length];
for (int i = 0; i < tasks.length; i++) {
printTasks[i] = new PrintTask(tasks[i], i, 0, tasks.length, lock);
}
for (PrintTask printTask : printTasks) {
printTask.start();
}
}
}
看一下运行结果:
没毛病,顺利输出了,然后再看看VisualVM:
VM01.png
虽然输出结果没问题,但是线程并没有严格的交替执行,是因为比如 A 在
unlock()
,下次具体会是另外的那一个线程 ( B or C ) 获得锁还不一定。如果是 B 拿到了,就会如期的打印,但是如果是 C 拿到,又不打印,然后就会继续让出,而有可能又给了 A , A 又会继续让出,直到 B 拿到并顺利打印。
也就是说因该给每一个线程加一个条件标记,让每次当前的线程打印完毕之后,能够准确的指定让给下一个应该打印的线程。
可以使用附随Lock
的 Condition
来解决这个问题:
网友评论