同步器

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();
	}
}

你可能感兴趣的:(concurrent)