CountDownLatch
通過基數來保證線程是否需要一直阻塞。
public class CountDownLatchExample {
private static int threadCount = 200;
public static void main(String[] args) throws InterruptedException {
ExecutorService exec = Executors.newCachedThreadPool();
final CountDownLatch countDownLatch = new CountDownLatch(threadCount);
for (int i=0; i<threadCount; i++) {
final int threadNum = i;
exec.execute(()->{
try {
test(threadNum);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
countDownLatch.countDown();
}
});
}
countDownLatch.await();
System.out.println("finish");
exec.shutdown();
}
private static void test(int threadNum) throws InterruptedException {
Thread.sleep(10);
System.out.println("thread number: " + threadNum);
}
}
Semaphore
信號量,可以控制併發訪問的線程個數,控制某個資源被同時訪問的個數,常用於僅能提供有限訪問的資源。下面代碼中的任務,只有大約30個線程中的任務會被執行,其餘因爲等待超時被丟棄。
public class SemaphoreExample1 {
// 併發線程數
private static int threadCount = 200;
public static void main(String[] args) {
// 線程池
final ExecutorService exec = Executors.newCachedThreadPool();
// 聲明信號量10個,表示控制併發訪問線程數爲10。
final Semaphore semaphore = new Semaphore(10);
for (int i=0; i<threadCount; i++) {
final int threadNum = i;
exec.execute(()->{
try {
// 嘗試獲取信號量,獲取不到等待30ms,等待後獲取不到則丟棄任務
if(semaphore.tryAcquire(30, TimeUnit.MILLISECONDS)) {
test(threadNum);
// 釋放信號量
semaphore.release();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
exec.shutdown();
}
private static void test(int threadNum) throws InterruptedException {
System.out.println(Thread No.: " +threadNum);
Thread.sleep(10);
}
}
CyclicBarrier
多個線程互相等待。在涉及固定線程數、這些線程必須彼此等待時,使用CyclicBarrier。之所以成爲cyclic,是因爲它可以reset後重新計數。
public class CyclicBarrierExample3 {
// 線程到達屏障時,優先執行runnable。
private static CyclicBarrier cyclicBarrier = new CyclicBarrier(5, ()->{
System.out.println("callback is running.");
});
public static void main(String[] args) throws InterruptedException {
ExecutorService exec = Executors.newCachedThreadPool();
int threadCount = 10;
for (int i=0; i<threadCount; i++) {
final int threadNum = i;
Thread.sleep(1000);
exec.execute(()->{
try {
race(threadNum);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
});
}
exec.shutdown();
}
private static void race(int threadNum) throws InterruptedException, BrokenBarrierException, TimeoutException {
Thread.sleep(1000);
System.out.println("Thread "+ threadNum + " is ready");
cyclicBarrier.await();
System.out.println("Thread "+ threadNum + " continue.");
}
}
ReentrantLock
和synchronized具有類似的屬性和性能,但使用時比synchronize複雜,使用不當會造成死鎖。僅在需要ReentrantLock的獨有功能時,才推薦使用。
ReentrantLock的獨有功能:
- 可指定是公平鎖還是非公平鎖。
- 提供了一個Condition類,可以分組喚醒需要喚醒的線程。
- 提供能夠中斷等待鎖的線程的機制,lock.lockInterruptibly()。
Future
通過Thread和Runnable創建的線程,在執行完成後無法獲得執行結果。通過Callable、Future和FutureTask可以獲得線程執行結果。
使用Future獲取線程執行結果:
public class FutureExample {
static class MyCallable implements Callable<String> {
@Override
public String call() throws InterruptedException {
System.out.println("do something in MyCallable");
Thread.sleep(5000);
return "Done";
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService exec = Executors.newCachedThreadPool();
Future<String> future = exec.submit(new MyCallable());
System.out.println("do something in main");
System.out.println("thread result: " + future.get());
}
}
使用FutureTask獲取線程執行結果,更簡單:
public class FutureTaskExample {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService exec = Executors.newCachedThreadPool();
FutureTask<String> futureTask = new FutureTask<String>(new Callable<String>() {
@Override
public String call() throws Exception {
System.out.println("do something in myCallable");
Thread.sleep(5000);
return "Done";
}
});
new Thread(futureTask).start();
System.out.println("do something in main");
System.out.println("thread result: " + futureTask.get());
}
}
BlockingQueue
阻塞隊列提供了四套方法進行插入、刪除和檢測,對不能立刻執行會有不同的反應。
Type | Throw Exception | Special Value | Blocks | Times Out |
---|---|---|---|---|
Insert | add(o) | offer(o) | put(o) | offer(o, timeout, timeunit) |
Remove | remove(o) | poll(o) | take(o) | poll(o, timeout, timeunit) |
Insert | element(o) | peek(o) |