這次整理了一些比較常用的線程工具類啦。
CountDownLatch:在一組線程執行完后,才能開始執行調用等待的線程。上片文章提到過junit的測試盡量不要測試線程,如果硬是要可以使用CountDownLatch進行測試
CyclicBarrier:在一組線程中調用等待方法后,只有這組所有線程都進入等待后,會執行一個指定的線程,在指定的線程執行完后,這組等待的線程才能繼續執行。
Semaphore:可用于限流使用。
Exchanger:當兩組線程都執行到交換的方法時,能將數據在這兩個線程之間進行數據交換。
CountDownLatch
該類實現主要是由一個內部類Sync實現的,Sync繼承了AbstractQueuedSynchronizer(就是經常提到的AQS),
常用的方法有兩個:
1.await():線程調用該方法進入帶阻塞狀態,只有當調用countDown()并驟減到0的時候,才能繼續執行
2.countDown():線程驟減一個單位。
具體實現:
?
public class CountDownLatchMain {static CountDownLatch latch = new CountDownLatch(6);static class InitThread implements Runnable{public void run() {try {TimeUnit.MILLISECONDS.sleep(200L);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("Thread name:"+Thread.currentThread().getName()+" init ...");latch.countDown();}}static class BusinessThread implements Runnable{public void run() {try {latch.await();} catch (InterruptedException e1) {e1.printStackTrace();}for(int i=0;i<3;i++) {try {TimeUnit.MILLISECONDS.sleep(100L);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Thread name : " + Thread.currentThread().getName()+" work_" + i);}}}public static void main(String[] args) throws InterruptedException {new Thread(new Runnable() {public void run() {latch.countDown();System.out.println("thread name "+Thread.currentThread().getName()+" 1st init ...");try {TimeUnit.MILLISECONDS.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}latch.countDown();System.out.println("thread name "+Thread.currentThread().getName()+" 2nd init ...");}},"Thread-0").start();new Thread(new BusinessThread()).start();for(int i=0;i<=4 ;i++) {new Thread(new InitThread()).start();}latch.await();TimeUnit.MILLISECONDS.sleep(300);System.out.println("main end ...");}
}
?執行結果:
thread name Thread-0 1st init ...
Thread name:Thread-1 init ...
Thread name:Thread-3 init ...
Thread name:Thread-2 init ...
Thread name:Thread-5 init ...
Thread name:Thread-4 init ...
Thread name : Thread-0 work_0
Thread name : Thread-0 work_1
Thread name : Thread-0 work_2
main end ...
thread name Thread-0 2nd init ...
CyclicBarrier
?
與CountDownLatch差不多,都是等待線程執行完后,才能繼續執行,不過這兩個不同的地方就是:CountDownLatch需要手動在邏輯代碼中進行驟減,減到臨界點后,阻塞的線程會繼續執行,而CountDownLatch是一組線程都進入到阻塞狀態后,然后執行指定線程執行完后,那組阻塞的線程才能繼續執行。 示例:
public class CyclicBarrierMain {static CyclicBarrier barrier = new CyclicBarrier(5,new Runnable() {public void run() {System.out.println("Thread name : " + Thread.currentThread().getName() + " barrier start...");try {TimeUnit.MILLISECONDS.sleep(100L);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("Thread name : " + Thread.currentThread().getName() + " barrier thread ...");}});static class SubThread implements Runnable{public void run() {long sleep = (long) (Math.random()*1000);System.out.println("thread name : " + Thread.currentThread().getName() + " init ...");try {TimeUnit.MILLISECONDS.sleep(sleep);} catch (InterruptedException e) {e.printStackTrace();}try {System.out.println("thread name : " + Thread.currentThread().getName() + " sleep time:"+sleep);barrier.await();} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}System.out.println("thread name : " + Thread.currentThread().getName() + " end ....");}}public static void main(String[] args) {for(int i =0 ; i<5;i++) {new Thread(new SubThread()).start();}}
}
執行結果:
thread name : Thread-2 init ...
thread name : Thread-4 init ...
thread name : Thread-1 init ...
thread name : Thread-0 init ...
thread name : Thread-3 init ...
thread name : Thread-2 sleep time:405
thread name : Thread-0 sleep time:488
thread name : Thread-1 sleep time:564
thread name : Thread-4 sleep time:777
thread name : Thread-3 sleep time:860
Thread name : Thread-3 barrier start...
Thread name : Thread-3 barrier thread ...
thread name : Thread-3 end ....
thread name : Thread-2 end ....
thread name : Thread-1 end ....
thread name : Thread-0 end ....
thread name : Thread-4 end ....
Semaphore
?
主要用于需要做限制的場景,比如限制連接池獲取次數等等,也有一個Sync內部類繼承了AQS
常用方法:
1、acquire():驟減一個單位,也可調用帶參的方法可指定減值,當驟減到0的時候,調用該方法會進入阻塞狀態。
2、release():釋放一個單位,也會在初始化的數量進行增加。
3、availablePermits():得到可獲取單位的數量。
4、getQueueLength():調用了acquire()方法并進入到阻塞狀態的總數量。
具體用法:
Semaphore semaphore = new Semaphore(5);
semaphore.acquire();//也可指定減少多個semaphore.acquire(2);
//...第6個acquire()方法時,再次調用將進入等待,直到在某個線程中執行了semaphore.release()方法才會繼續執行后面的
//...
Exchanger
主要用于兩個線程之間的數據交換,個人覺得這個用處不大,既然看到了這個,也就順便整理了一下
使用示例:
public class UseExcahnger {static Exchanger<Set<String>> exchanger = new Exchanger<Set<String>>();static class ThreadOne extends Thread{@Overridepublic void run() {Set<String> set = new HashSet<String>();set.add("1");set.add("2");try {System.out.println(Thread.currentThread().getName() + " > set:" + set);Thread.sleep(2000L);Set<String> exchange = exchanger.exchange(set);System.out.println(Thread.currentThread().getName() + " > " + exchange);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}static class ThreadTwo extends Thread{@Overridepublic void run() {Set<String> set = new HashSet<String>();set.add("3");set.add("4");try {System.out.println(Thread.currentThread().getName() + " > set:" + set);Thread.sleep(3000L);Set<String> exchange = exchanger.exchange(set);System.out.println(Thread.currentThread().getName() + " > " + exchange);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}public static void main(String[] args) {new ThreadOne().start();new ThreadTwo().start();}
}
執行結果為:
Thread-0 > set:[1, 2]
Thread-1 > set:[3, 4]
Thread-1 > [1, 2]
Thread-0 > [3, 4]
Future/FutureTask
這個在之前的提到過,與Callable一起使用,用來做回調的,個人覺得這個與之前的Fork/Join的分而治之有些相似,都是異步同時執行完后將結果返回,然后發現相似之后,回去看了一下源代碼
RecursiveAction和RecursiveTask<T>?都分別繼承了Future接口,而FutureTask也繼承了Future、Runnable,所以FutureTask既能作為Callable帶有返回結果,也能作為Thread去執行它。
這里就介紹一下類中的一些方法,示例的話可以翻看之前的文章
1、isDone():判斷線程是否已結束。
2、boolean cancel(boolean mayInterruptIfRunning):參數為true是中斷線程,但是只會發送中斷信號,在程序中需要自行判斷,參數為false則不會中斷,返回值為true,如果線程已結束或未開始則返回false。
3、isCancelled():判斷線程是否關閉。
4、get():獲取線程返回值。
好啦,就先整理這些啦,后面還有一些還在整理,后期會繼續分享的呀,如果有問題煩請各路大佬指出
?
?
?