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) |
Check | element(o) | peek(o) |