Latch 门闩
CountDownLatch 的一个有用特性是,它不要求调用 countDown 方法的线程等到计数到达零时才继续,
而在所有线程都能通过之前,它只是阻止任何线程继续通过一个 await。
计数无法被重置。 如果需要重置计数,请考虑使用 CyclicBarrier。
确保一组特定的活动在某一活动完成前,一直处于等待。比如:
1、在资源R初始化之前,使用该资源的所有活动都处于等待。
2、释放服务S前,完成所有依赖于S的服务。
3、开始多人游戏前,确保所有参与者的终端都连接完毕。
例子
public class TestHarness {
public long timeTasks(int nThreads, final Runnable task) throws InterruptedException {
final CountDownLatch startGate = new CountDownLatch(1);
final CountDownLatch endGate = new CountDownLatch(nThreads);
for (int i = 0; i < nThreads; i++) {
Thread t = new Thread() {
public void run() {
try {
startGate.await();
try {
task.run();
} finally {
endGate.countDown();
}
} catch (InterruptedException ignored) {
}
}
};
t.start();
}
long start = System.nanoTime();
System.out.println("open!");
startGate.countDown();
endGate.await();
System.out.println("close!");
long end = System.nanoTime();
return end - start;
}
public static void main(String[] ss) throws InterruptedException {
System.out.println(new TestHarness().timeTasks(10, new Thread() {
public void run() {
System.out.println("I am in!");
}
}));
}
}
FutureTask 未来的任务
可取消的异步计算。利用开始和取消计算的方法、查询计算是否完成的方法和获取计算结果的方法,此类提供了对Future的基本实现。
仅在计算完成时才能获取结果;如果计算尚未完成,则阻塞 get 方法。一旦计算完成,就不能再重新开始或取消计算。
三态:
waiting to run
running
completed
例子1
public class Preloader {
private ProductInfo loadProductInfo() throws DataLoadException {
System.out.println("load product information from a database...");
return null;
}
private final FutureTask future = new FutureTask(
new Callable() {
public ProductInfo call() throws DataLoadException {
return loadProductInfo();
}
});
private final Thread thread = new Thread(future);
public void start() {
thread.start();
System.out.println("thread is started.");
}
public ProductInfo get() throws DataLoadException, InterruptedException {
try {
return future.get();
} catch (ExecutionException e) {
Throwable cause = e.getCause();
if (cause instanceof DataLoadException)
throw (DataLoadException) cause;
else
throw LaunderThrowable.launderThrowable(cause);
}
}
interface ProductInfo {
}
public static void main(String[] ss) throws DataLoadException, InterruptedException{
Preloader loader=new Preloader();
loader.start();
System.out.println("---- ----");
loader.get();
}
}
class DataLoadException extends Exception {
private static final long serialVersionUID = 7984266484349694761L;
}
例子2
package creative.fire.concurrent.cache;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class ResourceCache {
private static ConcurrentHashMap> resourceMap = new ConcurrentHashMap>(
1000, 0.7f);
private Resource retrieveFromDB(String resId) {
Resource res = null;
System.out.println("retrieve " + resId + " from database.");
return res;
}
public Resource get(final String resId) throws InterruptedException,
ExecutionException {
FutureTask resTask = resourceMap.get(resId);
if (resTask != null){
System.out.println("get " + resId + " from cache.");
return resTask.get();
}
FutureTask newTask = new FutureTask(
new Callable() {
public Resource call() throws Exception {
return retrieveFromDB(resId);
}
});
FutureTask task = resourceMap.putIfAbsent(resId, newTask);
if (task == null) {
task = newTask;
task.run();
}
return task.get();
}
interface Resource {
}
public static void main(String[] ss) throws InterruptedException,ExecutionException {
ResourceCache cache = new ResourceCache();
cache.get("Device_ABC");
cache.get("Device_ABC");
}
}
Semaphore 信号
控制一组活动,它们在同一时间访问特定某一资源或者执行某个操作。
如有必要,在许可可用前会阻塞每一个 acquire(),然后再获取该许可。每个 release() 添加一个许可,从而可能释放一个正在阻塞的获取者。
Semaphore 通常用于限制可以访问某些资源(物理或逻辑的)的线程数目。
例子
public class SemaphoreBoundedBuffer {
private final Semaphore availableItems, availableSpaces;
@GuardedBy("this")
private final E[] items;
@GuardedBy("this")
private int putPosition = 0, takePosition = 0;
public SemaphoreBoundedBuffer(int capacity) {
if (capacity <= 0)
throw new IllegalArgumentException();
availableItems = new Semaphore(0);
availableSpaces = new Semaphore(capacity);
items = (E[]) new Object[capacity];
}
public boolean isEmpty() {
return availableItems.availablePermits() == 0;
}
public boolean isFull() {
return availableSpaces.availablePermits() == 0;
}
public void put(E x) throws InterruptedException {
if (availableSpaces.tryAcquire(2, TimeUnit.SECONDS)) {
System.out.println("availableSpaces acquire");
System.out.println("available Spaces="+availableSpaces.availablePermits());
doInsert(x);
availableItems.release();
System.out.println("availableItems release");
System.out.println("available Items="+availableItems.availablePermits());
} else {
System.out.println("time out.");
}
}
public E take() throws InterruptedException {
// availableItems.acquire();
if (availableItems.tryAcquire(2, TimeUnit.SECONDS)) {
System.out.println("availableItems acquire");
System.out.println("available Items="+availableItems.availablePermits());
E item = doExtract();
availableSpaces.release();
System.out.println("availableSpaces release");
System.out.println("available Spaces="+availableSpaces.availablePermits());
return item;
} else {
System.out.println("time out.");
return null;
}
}
private synchronized void doInsert(E x) {
int i = putPosition;
items[i] = x;
putPosition = (++i == items.length) ? 0 : i;
System.out.println("insert " + x);
}
private synchronized E doExtract() {
int i = takePosition;
E x = items[i];
items[i] = null;
takePosition = (++i == items.length) ? 0 : i;
System.out.println("extract " + x);
return x;
}
public static void main(String[] ss) throws InterruptedException {
final SemaphoreBoundedBuffer buffer = new SemaphoreBoundedBuffer(
2);
buffer.put(1);
System.out.println("---- ----");
buffer.put(2);
System.out.println("---- ----");
buffer.put(3);
System.out.println("---- ----");
buffer.take();
System.out.println("---- ----");
buffer.take();
System.out.println("---- ----");
buffer.take();
}
}
Barrier 路障
它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier。
门闩用来等待事件,路障用来等待其他线程。
门闩当计数减到0时,执行await后的代码;路障是当await数量到达设定数量后,才继续往下执行。
例子
public class CyclicBarrierTest {
public static void main(String[] args) throws InterruptedException,
BrokenBarrierException {
int count = Runtime.getRuntime().availableProcessors();
System.out.println("available processors = " + count);
if (count == 1)
count = 4;
final CyclicBarrier barrier = new CyclicBarrier(count, new Runnable() {
@Override
public void run() {
System.out.println("figure out what they are doing next.");
}
});
ExecutorService exec = Executors.newFixedThreadPool(count);
while (count > 0) {
exec.execute(new Thread(count + "") {
public void run() {
System.out.println(getName() + " gets McDonald");
try {
barrier.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
Thread.sleep(500);
count--;
}
exec.shutdown();
}
}