大連網(wǎng)站制作網(wǎng)頁出售外鏈
我覺得是一個很高頻的面試題,ABCD四個線程,A線程要等到BCD線程執(zhí)行完再執(zhí)行,怎么做
因為我剛復習完AQS,所以立馬想到了CountDownLatch,但是看面試官反應他最想聽到的應該是join方法,所以面試后就總結(jié)了幾種方法。
1、join
2、CountDownLatch
3、核心線程數(shù)為1的線程池
1、Join方法
Thread提供了讓一個線程等待另一個線程完成的方法——join方法。當在某個程序執(zhí)行流中調(diào)用其他線程的join方法時,調(diào)用線程將被阻塞,直到被調(diào)用join方法加入的join線程執(zhí)行完畢
public class ThreadJoinDemo {public static void main(String[] args) throws InterruptedException {Thread B = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("B線程啟動");}});Thread C = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("C線程啟動");}});Thread D = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("D線程啟動");}});Thread A = new Thread(new Runnable() {@Overridepublic void run() {try {B.join();C.join();D.join();} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("A線程啟動");}});A.start();D.start();C.start();B.start();}
}
結(jié)果:
D線程啟動
C線程啟動
B線程啟動
A線程啟動
2、CountDownLatch
CountDownLatch(閉鎖)是一個同步協(xié)助類,允許一個或者多個線程等待,直到其他線程完成操作集。
CountDownLatch使用給定的數(shù)值(count)初始化,await方法會阻塞直到當前的計數(shù)值(count)由于countDown方法的調(diào)用達到0,count為0后所有等待的線程都會被釋放,并且隨后對await方法的調(diào)用都會立即返回,這個是個一次性的現(xiàn)象(相比CyclicBarrier會重置count)。
public class ThreadCountDownLatchDemo {public static void main(String[] args) {CountDownLatch countDownLatch = new CountDownLatch(3);new Thread(()->{countDownLatch.countDown();System.out.println("線程B啟動");}).start();new Thread(()->{countDownLatch.countDown();System.out.println("線程C啟動");}).start();new Thread(()->{countDownLatch.countDown();System.out.println("線程D啟動");}).start();new Thread(()->{try {countDownLatch.await();} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("線程A啟動");}).start();}
}
結(jié)果:
線程B啟動
線程C啟動
線程D啟動
線程A啟動
CountDownLatch與Thread.join的區(qū)別
- CountDownLatch的作用就是允許一個或多個線程等待其他線程完成操作,看起來有點類似join() 方法,但其提供了比 join() 更加靈活的API。
- CountDownLatch可以手動控制在n個線程里調(diào)用n次countDown()方法使計數(shù)器進行減一操作,也可以在一個線程里調(diào)用n次執(zhí)行減一操作。
- 而 join() 的實現(xiàn)原理是不停檢查join線程是否存活,如果 join 線程存活則讓當前線程永遠等待。所以兩者之間相對來說還是 countDownLatch使用起來較為靈活。
3、線程池
JAVA通過Executors提供了四種線程池
單線程化線程池(newSingleThreadExecutor);
可控最大并發(fā)數(shù)線程池(newFixedThreadPool);
可回收緩存線程池(newCachedThreadPool);
支持定時與周期性任務的線程池(newScheduledThreadPool)。
單線程化線程池(newSingleThreadExecutor):優(yōu)點,串行執(zhí)行所有任務。
submit():提交任務。
shutdown():方法用來關閉線程池,拒絕新任務。
使用核心線程數(shù)為1的線程池,保證線程的執(zhí)行順序按照線程的提交順序執(zhí)行。
應用場景:串行執(zhí)行所有任務。如果這個唯一的線程因為異常結(jié)束,那么會有一個新的線程來替代它。此線程池保證所有任務的執(zhí)行順序按照任務的提交順序執(zhí)行。
public class ThreadPoolDemo {public static void main(String[] args) {ExecutorService executorService = Executors.newSingleThreadExecutor();
// ExecutorService executorService1 = Executors.newFixedThreadPool(1);Thread A = new Thread(() -> {System.out.println("啟動線程A");});Thread B = new Thread(() -> {System.out.println("啟動線程B");});Thread C = new Thread(() -> {System.out.println("啟動線程C");});Thread D = new Thread(() -> {System.out.println("啟動線程D");});executorService.submit(D);executorService.submit(C);executorService.submit(B);executorService.submit(A);executorService.shutdown();}
}
結(jié)果:
啟動線程D
啟動線程C
啟動線程B
啟動線程A