筆/面試的時候常常遇到的一個問題,就是多個線程進行交替的打印任務:
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();
}
}
}
看一下運行結果:
res.png
沒毛病,順利輸出了藏雏,然后再看看VisualVM:
VM01.png
雖然輸出結果沒問題拷况,但是線程并沒有嚴格的交替執(zhí)行,是因為比如 A 在
unlock()
掘殴,下次具體會是另外的那一個線程 ( B or C ) 獲得鎖還不一定赚瘦。如果是 B 拿到了,就會如期的打印奏寨,但是如果是 C 拿到起意,又不打印,然后就會繼續(xù)讓出病瞳,而有可能又給了 A 揽咕, A 又會繼續(xù)讓出,直到 B 拿到并順利打印套菜。
也就是說因該給每一個線程加一個條件標記亲善,讓每次當前的線程打印完畢之后,能夠準確的指定讓給下一個應該打印的線程逗柴。
可以使用附隨Lock
的 Condition
來解決這個問題: