1 Thread,Runnable來操作多線程
----------------------------------------------------------------------------------------------------------------------------------------------------------
2 CountDownLatch(閉鎖)
JDk1.5提供了一個非常有用的包,Concurrent包,這個包主要用來操作一些併發操作,提供一些併發類,可以方便在項目當中傻瓜式應用。
JDK1.5以前,使用併發操作,都是通過Thread,Runnable來操作多線程;但是在JDK1.5之後,提供了非常方便的線程池(ThreadExecutorPool),主要代碼由大牛Doug Lea完成,其實是在jdk1.4時代,由於java語言內置對多線程編程的支持比較基礎和有限,所以他寫了這個,因爲實在太過於優秀,所以被加入到jdk之中;
這次主要對CountDownLatch進行系統的講解
使用場景:比如對於馬拉松比賽,進行排名計算,參賽者的排名,肯定是跑完比賽之後,進行計算得出的,翻譯成Java識別的預發,就是N個線程執行操作,主線程等到N個子線程執行完畢之後,在繼續往下執行。
代碼示例
1 public static void testCountDownLatch(){ 2 3 int threadCount = 10; 4 5 final CountDownLatch latch = new CountDownLatch(threadCount); 6 7 for(int i=0; i< threadCount; i++){ 8 9 new Thread(new Runnable() { 10 11 @Override 12 public void run() { 13 14 System.out.println("線程" + Thread.currentThread().getId() + "開始出發"); 15 16 try { 17 Thread.sleep(1000); 18 } catch (InterruptedException e) { 19 e.printStackTrace(); 20 } 21 22 System.out.println("線程" + Thread.currentThread().getId() + "已到達終點"); 23 24 latch.countDown(); 25 } 26 }).start(); 27 } 28 29 try { 30 latch.await(); 31 } catch (InterruptedException e) { 32 e.printStackTrace(); 33 } 34 35 System.out.println("10個線程已經執行完畢!開始計算排名"); 36 }
執行結果:
線程10開始出發
線程13開始出發
線程12開始出發
線程11開始出發
線程14開始出發
線程15開始出發
線程16開始出發
線程17開始出發
線程18開始出發
線程19開始出發
線程14已到達終點
線程15已到達終點
線程13已到達終點
線程12已到達終點
線程10已到達終點
線程11已到達終點
線程16已到達終點
線程17已到達終點
線程18已到達終點
線程19已到達終點
10個線程已經執行完畢!開始計算排名
源碼分析:
1、CountDownLatch:A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.
大致意思:也就是說主線程在等待所有其它的子線程完成後再往下執行
2、構造函數:CountDownLatch(int count)//初始化count數目的同步計數器,只有當同步計數器爲0,主線程纔會向下執行
主要方法:void await()//當前線程等待計數器爲0
boolean await(long timeout, TimeUnit unit)//與上面的方法不同,它加了一個時間限制。
void countDown()//計數器減1
long getCount()//獲取計數器的值
3.它的內部有一個輔助的內部類:sync.
它的實現如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
/** *
Synchronization control For CountDownLatch. *
Uses AQS state to represent count. */ private static final class Sync extends AbstractQueuedSynchronizer
{ private static final long serialVersionUID
= 4982264981922014374L; Sync( int count)
{ setState(count); } int getCount()
{ return getState(); } protected int tryAcquireShared( int acquires)
{ return (getState()
== 0 )
? 1 :
- 1 ; } protected boolean tryReleaseShared( int releases)
{ //
Decrement count; signal when transition to zero for (;;)
{ int c
= getState(); if (c
== 0 ) return false ; int nextc
= c- 1 ; if (compareAndSetState(c,
nextc)) return nextc
== 0 ; } } } |
4.await()方法的實現
sync.acquireSharedInterruptibly(1);
-->if (tryAcquireShared(arg) < 0)//調用3中的tryAcquireShared()方法
doAcquireSharedInterruptibly(arg);//加入到等待隊列中
5.countDown()方法的實現
sync.releaseShared(1);
--> if (tryReleaseShared(arg))//調用3中的tryReleaseShared()方法
doReleaseShared();//解鎖
參考文章:
https://my.oschina.net/u/1185331/blog/502350
http://blog.itpub.net/30024515/viewspace-1432825/
====================================================================================
3 ExecutorService extends Executor
ExecutorService executor = Executors.newFixedThreadPool(MAX_POOL_SIZE);
while (iterator.hasNext()) {
LBHostInfoVOMongo mongo = iterator.next();
executor.execute(new Runnable() {
@Override
public void run() {
try {
dao.addLBInfoMonitorResult(mongo, startTime, endTime, time_stamp);
} catch (Exception e) {
logger.error(UTrace.trace(e));
}
}
});
}
executor.shutdown();
---------------------------------------
ExecutorService(線程池)可以被關閉來拒絕新任務。有兩個不同的方法來關閉。
shutdown方法 在關閉 ExecutorService 之前等待提交的任務執行完成。
shutdownNow方法 會阻止開啓新的任務並且嘗試停止當前正在執行的線程,一旦調用該方法,線程池中將沒有激活的任務,沒有等待執行的任務,也沒有新任務提交。
沒有任務執行的ExecutorService將會被回收。
方法submit擴展了Executor.execute(Runnable) 方法, 創建並返回一個 Future 結果,這個Future可以取消任務的執行或者等待完成得到返回值。
方法invokeAny and invokeAll 可以執行一組任務,等待至少一個任務或者多個任務完成(ExecutorCompletionService擴展了這些方法的實現)。
===============================================================================
4 executor.submit()
Future<GenericResponse> future = executor.submit(new Callable<GenericResponse>() {
@Override
public GenericResponse call() throws Exception {
return callbackSaveLog(req);
}
});
/**
* 負載均衡創建
* @author jz
* @date 2017年9月6日 下午7:49:33
* @param request
* @param response void
*/
@RequestMapping(value = "create")
public void create(HttpServletRequest request, HttpServletResponse response) {
try {
CommonInstanceCreateDTO req = URequest.getObject(request, CommonInstanceCreateDTO.class);
logger.debug(UJson.toString(req));
Future<GenericResponse> future = executor.submit(new Callable<GenericResponse>() {
@Override
public GenericResponse call() throws Exception {
return loadBalanceCreateService.handleCreateArrow(req);
}
});
UResponse.json(future.get(), response);
} catch (Throwable e) {
logger.error(UTrace.trace(e));
UResponse.json(ISmartResponses.SYSTEM_ERROR, response);
}
}
<T> Future<T> submit(Callable<T> task);
- 1
提交一個帶有返回值的任務(Callable),返回值爲Future,表示了任務的執行完成結果,Future.get()方法返回成功執行後的結果。
如果你想要阻塞當前線程知道執行完成返回結果,那麼你可以這樣做:
result = exec.submit(aCallable).get();
<T> Future<T> submit(Runnable task, T result);
- 1
提交一個Runnable任務執行,返回一個Future做爲任務task的代理,Future.get()方法在執行成功後可以返回結果。
Runnable task 提交的任務
T results 執行的結果
==================================================================================================
5