掌握這四種方法,多線程按序執(zhí)行不再是問題
目錄
- 在子線程中通過join()方法指定順序
- 在主線程中通過join()方法指定順序
- 通過倒數(shù)計(jì)時(shí)器CountDownLatch實(shí)現(xiàn)
- 通過創(chuàng)建單一化線程池newSingleThreadExecutor()實(shí)現(xiàn)
在子線程中通過join()方法指定順序
通過join()方法使當(dāng)前線程“阻塞”,等待指定線程執(zhí)行完畢后繼續(xù)執(zhí)行。
舉例:在線程thread2中,加上一句thread1.join(),其意義在于,當(dāng)前線程2運(yùn)行到此行代碼時(shí)會(huì)進(jìn)入阻塞狀態(tài),直到線程thread1執(zhí)行完畢后,線程thread2才會(huì)繼續(xù)運(yùn)行,這就保證了線程thread1與線程thread2的運(yùn)行順序。
public class ThreadJoinDemo {
public static void main(String[] args) throws InterruptedException {
final Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("打開冰箱!");
}
});
final Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
try {
thread1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("拿出一瓶牛奶!");
}
});
final Thread thread3 = new Thread(new Runnable() {
@Override
public void run() {
try {
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("關(guān)上冰箱!");
}
});
//下面三行代碼順序可隨意調(diào)整,程序運(yùn)行結(jié)果不受影響,因?yàn)槲覀冊(cè)谧泳€程中通過“join()方法”已經(jīng)指定了運(yùn)行順序。
thread3.start();
thread2.start();
thread1.start();
}
}
運(yùn)行結(jié)果:
打開冰箱!
拿出一瓶牛奶!
關(guān)上冰箱!
在主線程中通過join()方法指定順序
簡(jiǎn)單說一下子線程與主線程的區(qū)別,子線程指的是發(fā)生在Thread內(nèi)部的代碼,主線程指的是發(fā)生在main函數(shù)中的代碼,我們可以在main函數(shù)中通過join()方法讓主線程阻塞等待以達(dá)到指定順序執(zhí)行的目的。
public class ThreadMainJoinDemo {
public static void main(String[] args) throws InterruptedException {
final Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("打開冰箱!");
}
});
final Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("拿出一瓶牛奶!");
}
});
final Thread thread3 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("關(guān)上冰箱!");
}
});
thread1.start();
thread1.join();
thread2.start();
thread2.join();
thread3.start();
}
}
輸出結(jié)果:
打開冰箱!
拿出一瓶牛奶!
關(guān)上冰箱!
通過倒數(shù)計(jì)時(shí)器CountDownLatch實(shí)現(xiàn)
CountDownLatch通過計(jì)數(shù)器提供了更靈活的控制,只要檢測(cè)到計(jì)數(shù)器為0當(dāng)前線程就可以往下執(zhí)行而不用管相應(yīng)的thread是否執(zhí)行完畢。
public class ThreadCountDownLatchDemo {
private static CountDownLatch countDownLatch1 = new CountDownLatch(1);
private static CountDownLatch countDownLatch2 = new CountDownLatch(1);
public static void main(String[] args) {
final Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("打開冰箱!");
countDownLatch1.countDown();
}
});
final Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
try {
countDownLatch1.await();
System.out.println("拿出一瓶牛奶!");
countDownLatch2.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
final Thread thread3 = new Thread(new Runnable() {
@Override
public void run() {
try {
countDownLatch2.await();
System.out.println("關(guān)上冰箱!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
//下面三行代碼順序可隨意調(diào)整,程序運(yùn)行結(jié)果不受影響
thread3.start();
thread1.start();
thread2.start();
}
}
輸出結(jié)果:
打開冰箱!
拿出一瓶牛奶!
關(guān)上冰箱!
通過創(chuàng)建單一化線程池newSingleThreadExecutor()實(shí)現(xiàn)
單線程化線程池(newSingleThreadExecutor)的優(yōu)點(diǎn),串行執(zhí)行所有任務(wù)。
public class ThreadPoolDemo {
static ExecutorService executorService = Executors.newSingleThreadExecutor();
public static void main(String[] args) {
final Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("打開冰箱!");
}
});
final Thread thread2 =new Thread(new Runnable() {
@Override
public void run() {
System.out.println("拿出一瓶牛奶!");
}
});
final Thread thread3 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("關(guān)上冰箱!");
}
});
executorService.submit(thread1);
executorService.submit(thread2);
executorService.submit(thread3);
executorService.shutdown(); //使用完畢記得關(guān)閉線程池
}
}
輸出結(jié)果:
打開冰箱!
拿出一瓶牛奶!
關(guān)上冰箱!