場景如下:一共三個線程a,b,c,其中c需要用到a,b,執行的結果,應該怎麼處理?
1)CountDownLatch,主線程中調用await方法,每個線程調用countdown
上面兩種方法需要分别調用多次join或future的get方法,不太好,有一種方法是使用CountDownLatch類
認知CountDownLatch的方法:
await():阻塞主線程,直到countDownLatch的計數器減少到0的位置,
countDown:将目前的計數器減1
getCount:傳回目前的數
思路如下:讓a,b線程使用CountDowmLatch,然後執行countDownLatch的await方法
主類:
public static void main(String[] args) {
CountDownLatch countDownLaunch = new CountDownLatch(5);
for(int i=1;i<6;i++){
ThreadWithCountDownLatch threadWithCountDownLatch = new ThreadWithCountDownLatch(i*1000L,countDownLaunch,"THREAD"+i);
Thread thread = new Thread(threadWithCountDownLatch);
thread.start();
}
mainThreadWork();
try {
countDownLaunch.await();//下面的代碼要等待所有的countDown的計數器為零再執行
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("all done");
}
線程類:
public class ThreadWithCountDownLatch implements Runnable{
long time;
CountDownLatch countDownLatch;
String name;
public ThreadWithCountDownLatch(long time,CountDownLatch countDownLatch,String name){
this.time=time;
this.countDownLatch = countDownLatch;
this.name=name;
}
@Override
public void run() {
try {
System.out.println(name+" start");
work(time);
System.out.println(name+" end");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
countDownLatch.countDown();
}
}
private void work(long time2) throws InterruptedException {
Thread.sleep(time2);
}
}
2)CyclicBarrier-每個線程中調用await,調用達到次數再一起放行
調用栅欄(計數器為5)的await,相當于告訴栅欄已經有一個線程到達栅欄,同時線程本身不再繼續執行;當cyclicBarrier的await方法調用5次時,所有線程繼續執行,同時觸發栅欄的run方法
主類:
public static void main(String[] args) {
CyclicBarrier cylicBarrier = new CyclicBarrier(5,new Runnable() {
//栅欄動作,在計數器為零的時候執行
@Override
public void run() {//栅欄的await方法執行五次後會調用此處
// TODO Auto-generated method stub
System.out.println("all work done");
}
});
ExecutorService pool = Executors.newFixedThreadPool(5);
for(int i=1;i<6;i++){
pool.submit(new ThreadWithCyclicBarrier(i,cylicBarrier));
}
pool.shutdown();
System.out.println("last ");
}
線程類:
public class ThreadWithCyclicBarrier implements Runnable{
int id;
CyclicBarrier cyclicBarrier;
public ThreadWithCyclicBarrier(int id,CyclicBarrier cyclicBarrier){
this.id = id;
this.cyclicBarrier=cyclicBarrier;
}
@Override
public void run() {
System.out.println("thread"+id+" start");
try {
cyclicBarrier.await();//栅欄計數值為零後會繼續執行
Thread.sleep(1000L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("thread"+id+" end");
}
}
3)join方法實作
對a,b使用a.join()和b.join(); 然後下面使用c.start()
SubTThread subthread = new SubTThread("subthread");
SubTThread subthread2 = new SubTThread("subthread2");
SubTThread subthread3 = new SubTThread("subthread3");
Thread thread = new Thread(subthread);
Thread thread2 = new Thread(subthread2);
Thread thread3 = new Thread(subthread3);
thread.start();
thread2.start();
mainThreadWork();
System.out.println("wait subthread done");
try {
thread.join();
thread2.join();//當thread和thread2的run方法執行完畢後才會繼續下面的代碼
} catch (InterruptedException e) {
e.printStackTrace();
}
thread3.start();
System.out.println("all work done");
4)線程池submit線程傳回Future,并調用future的get方法
使用線程池,線程池submit線程傳回Future,并調用future的get方法.則get方法下的代碼都需要等待調用了get方法的線程完全執行後再執行
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(3);
SubTThreadByRun subthread = new SubTThreadByRun("subthread");
SubTThreadByRun subthread2 = new SubTThreadByRun("subthread2");
Thread thread = new Thread(subthread);
Thread thread2 = new Thread(subthread2);
ThreadByCall threadByCall = new ThreadByCall("call1");
Future future1 = pool.submit(thread);
Future future2 = pool.submit(thread2);
Future future3 = pool.submit(threadByCall);
mainThreadWork();
try {
future1.get();
future2.get();
String str = (String) future3.get();//下面的代碼需要等待thread1/thread2和threadByCall 執行完畢後執行下面的代碼
System.out.println("得到結果:"+str);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
SubTThreadByRun subthread3 = new SubTThreadByRun("subthread3");
Thread thread3 = new Thread(subthread3);
thread3.start();
System.out.println("all work done");
pool.shutdown();//關閉線程池
}
四種實作方式比較
join--适用于少量線程
線程池submit+future.get--适用于實際使用的線程數量不定,且所有線程執行完畢
CountDownLatch--設定線程數,每個線程結尾使用countDown()方法減值,主線程中調用await方法來阻塞,當資料減為0時,主線程繼續執行,适用于實際使用線程數量固定
栅欄--多個線程都執行到某個點暫停,然後再一起開始,并且增加栅欄的run方法
new CyclicBarrier(5,new Runnable());每個線程執行到CyclicBarrier.await方法,線程會暫停,當await方法執行5次時,所有線程繼續運作,并且執行cyclicBarrier的runner的run方法