怎樣應用呢?主要是把工序安排好。
比如,想泡壺茶喝。當時的情況是:開水沒有;水壺要洗,茶壺、茶杯要洗;火已生了,茶葉也有了。怎麼辦?
辦法甲:洗好水壺,灌上涼水,放在火上;在等待水開的時間裡,洗茶壺、洗茶杯、拿茶葉;等水開了,泡茶喝。
辦法乙:先做好一些準備工作,洗水壺,洗茶壺茶杯,拿茶葉;一切就緒,灌水燒水;坐待水開了,泡茶喝。
辦法丙:洗淨水壺,灌上涼水,放在火上,坐待水開;水開了之後,急急忙忙找茶葉,洗茶壺茶杯,泡茶喝。
哪一種辦法省時間?我們能一眼看出,第一種辦法好,後兩種辦法效率較低。
水壺不洗,不能燒開水,因而洗水壺是燒開水的前提。沒開水、沒茶葉、不洗茶壺茶杯,就不能泡茶,因而這些又是泡茶的前提。它們的相互關係,可以用下邊的箭頭圖來表示:
從這個圖上可以一眼看出,辦法甲總共要16分鐘(而辦法乙、丙需要20分鐘)。如果要縮短工時、提高工作效率,應當主要抓燒開水這個環節,而不是抓拿茶葉等環節。同時,洗茶壺茶杯、拿茶葉總共不過4分鐘,大可利用「等水開」的時間來做。
洗茶壺,洗茶杯,拿茶葉,或先或後,關係不大,而且同是一個人的活兒,因而可以合併成為:
文中辦法乙、丙都相當於任務序列
而圖一相當於啟動了 4 個執行緒,有點浪費
@Slf4j(topic = "c.Test16")
public class Test16 {
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
log.debug("洗水壺");
// TimeUnit.SECONDS.sleep(i);
sleep(1); // sleep 1s 可使用上方的程式碼睡眠
log.debug("燒開水");
sleep(5); // sleep 5s
},"老王");
Thread t2 = new Thread(() -> {
log.debug("洗茶壺");
sleep(1); // sleep 1s
log.debug("洗茶杯");
sleep(2); // sleep 2s
log.debug("拿茶葉");
sleep(1); // sleep 1s
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("泡茶");
},"小王");
t1.start();
t2.start();
}
}
輸出
解法1 的缺陷:
上面模擬的是小王等老王的水燒開了,小王泡茶,如果反過來要實現老王等小王的茶葉拿來了,老王泡茶呢?程式碼最好能適應兩種情況
上面的兩個執行緒其實是各執行各的,如果要模擬老王把水壺交給小王泡茶,或模擬小王把茶葉交給老王泡茶呢
class S2 {
static String kettle = "冷水";
static String tea = null;
static final Object lock = new Object();
static boolean maked = false;
public static void makeTea() {
new Thread(() -> {
log.debug("洗水壺");
sleep(1);
log.debug("燒開水");
sleep(5);
synchronized (lock) {
kettle = "開水";
lock.notifyAll();
while (tea == null) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (!maked) {
log.debug("拿({})泡({})", kettle, tea);
maked = true;
}
}
}, "老王").start();
new Thread(() -> {
log.debug("洗茶壺");
sleep(1);
log.debug("洗茶杯");
sleep(2);
log.debug("拿茶葉");
sleep(1);
synchronized (lock) {
tea = "花茶";
lock.notifyAll();
while (kettle.equals("冷水")) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (!maked) {
log.debug("拿({})泡({})", kettle, tea);
maked = true;
}
}
}, "小王").start();
}
}
輸出
20:04:48.179 c.S2 [小王] - 洗茶壺
20:04:48.179 c.S2 [老王] - 洗水壺
20:04:49.185 c.S2 [老王] - 燒開水
20:04:49.185 c.S2 [小王] - 洗茶杯
20:04:51.185 c.S2 [小王] - 拿茶葉
20:04:54.185 c.S2 [老王] - 拿(開水)泡(花茶)
解法2 解決了解法1 的問題,不過老王和小王需要相互等待,不如他們只負責各自的任務,泡茶交給第三人來做
class S3 {
static String kettle = "冷水";
static String tea = null;
static final Object lock = new Object();
public static void makeTea() {
new Thread(() -> {
log.debug("洗水壺");
sleep(1);
log.debug("燒開水");
sleep(5);
synchronized (lock) {
kettle = "開水";
lock.notifyAll();
}
}, "老王").start();
new Thread(() -> {
log.debug("洗茶壺");
sleep(1);
log.debug("洗茶杯");
sleep(2);
log.debug("拿茶葉");
sleep(1);
synchronized (lock) {
tea = "花茶";
lock.notifyAll();
}
}, "小王").start();
new Thread(() -> {
synchronized (lock) {
while (kettle.equals("冷水") || tea == null) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug("拿({})泡({})", kettle, tea);
}
}, "王夫人").start();
}
}
輸出
20:13:18.202 c.S3 [小王] - 洗茶壺
20:13:18.202 c.S3 [老王] - 洗水壺
20:13:19.206 c.S3 [小王] - 洗茶杯
20:13:19.206 c.S3 [老王] - 燒開水
20:13:21.206 c.S3 [小王] - 拿茶葉
20:13:24.207 c.S3 [王夫人] - 拿(開水)泡(花茶)
本文來自部落格園,作者:|舊市拾荒|,轉載請註明原文連結:https://www.cnblogs.com/xiaoyh/p/17092390.html