同步工具类

1、闭锁(Latch)

2、信号量(Semaphore)

3、栅栏(Barrier)

1、闭锁(Latch):作用相当于一扇门:在闭锁到达结束之前,这扇门一直 是关闭的,并且没有任何线程能通过,当到达结束状态时,这扇门会打开并允许所有的线程通过。当闭锁到达结束状态后,将不会再改变状态,因此这扇门将保持永远打开状态(意思是指:一旦进入终止状态,就不能被重置,简单地说就是一次性的)。闭锁可以用来确保某些活动直到其它活动都完成后才继续执行。

eg:确保某个计算再起需要的所有资源都被初始化之后才继续执行。

     确保某个读物再起依赖的所有其它服务都 已经启动后才启动。

    等待直到某个操作的额所有参与者都就绪再继续执行(eg:多玩家游戏中的所有玩家)。

     

CountDownLatch就是一种闭锁实现,它可以使一个或者多个线程等待一组事件发生。如图

首先构造方法CountDownLatch(int count);这个count计数器(正数)表示需要等待的事件数量。

countDown()方法就是将count递减,表示有一个事件已经发生了。

await()方法就是等待count到达0,这表示所有需要等待的事件都已经发生。如果count计数器的值非零,那么await()会一直阻塞到计数器为零,或者等待中的线程中断,或者等待超时。

闭锁的两种常见用法:如TestHarness ,StartGate和EndGate两个闭锁,每个工作线程在气动门上等待,从而保证所以线程但都就绪后才开始执行。而每个工作线程最后做的一件事就是调用EndGate的countDown。从而保证主线程高效的等待所有工作线程都执行完成。启动门(startGate)将使得主线程能够同时释放所有工作线程,结束门(EndGate)能够等待最后一个线程执行完成,而不是顺序的等待每个线程执行完成。因此可以统计所消耗的时间

 

package simple;


import java.util.concurrent.CountDownLatch;


public class TestHarness {
	public long timeTask(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 e) {
						e.printStackTrace();
					}
				}
			};
			t.start();
		}end for
		
		long start = System.nanoTime();
		startGate.countDown();
		endGate.await();
		long end = System.nanoTime();
		return end -start;
	}
	public static void main(String []args){
		TestHarness th = new TestHarness(); 
		long time = 0;
		try {
			  time = th.timeTask(10, new Thread(){
				public void run(){
					for(int i = 0;i<10000; ++i){}
				}
			});
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("历时"+time+"纳秒");
	}
}

FutureTask也可以用作闭锁。一种可生成结果的计算(A cancellable asynchronous computation)。通过实现接口RunnableFuture,而接口RunnableFuture继承了Runnable, Future两个接口。其相关方法如图

cancel()方法尝试中断。当task还未开始,调用cancel后该task就不再运行了。但当task已启动后,cancel(boolean)传进的参数决定在尝试取消该task是否应该被中断( If the task has already started, then the mayInterruptIfRunning parameter determines whether the thread executing this task should be interrupted in an attempt to stop the task.)。

get()方法的行为取决于task的状态,如果task已经完成,则get立即返回结果,否则get将一直阻塞到task进入完成状态,然后返回结果或者抛出异常。

run()方法就是执行计算逻辑。task的状态转换就是由此变化的。如果run()方法未执行,则task状态处于还没执行。run()方法已经执行则task状态包含已完成状态,正在执行状态,取消结束状态,异常状态。

FutureTask 可以用来执行以下时间比较长的计算,

 

package simple;


import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;


public class PreLoader {
	private final FutureTask<Long> future = new FutureTask(new Callable<Long>(){
		public Long call() throws InterruptedException{
			Thread.sleep(10000);
			return new Long(1234);
		}
	});
	private final Thread th = new Thread(future);
	public void start(){
		th.start();
	}
	public Long load(){
		new Thread(){
			public void run(){
				try {
					Thread.sleep(10000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}.start();
		
		return new Long(123);
	}
	public Long get() throws InterruptedException{
		System.out.println("start calculating.......");
		long start = System.nanoTime();
		Long oj = null;
		try {
			oj =  future.get();
		} catch (ExecutionException e) {
			Throwable cause = e.getCause();
			if(cause instanceof RuntimeException){
				throw (RuntimeException)cause;
			}else if(cause instanceof Error){
				throw (Error)cause;
			}
		}
		long end = System.nanoTime();
		System.out.println("耗时:"+(end-start)+"纳秒得到"+oj);
		return oj;
	}
	public static void main(String []args) throws InterruptedException{
		PreLoader pl = new PreLoader();
		pl.start();
		long begin = System.nanoTime();
		pl.get();
		long end = System.nanoTime();
		System.out.println("等待了"+(end-begin));
	}
}

信号量(Semaphore):Semaphore中管理着一组虚拟的许可(permit),许可的初数量可通过构造函数来指定,在执行操作时可以首先获得许可(只要还要有剩余的许可,没有许可,那么将一直阻塞直到由许可),使用后再释放许可。用来控制同时访问某个特定资源的操作数量,或者同时执行某个指定操作的数量。还可以用来实现某种资源池,或者对容器加边界。

 

Semaphore(int,boolean)构造方法,int参数表示有多少个许可,boolean参数表示许可是否以先进先出(FIFO)的次序处理许可。默认是无序的。计算信号量的一种简化形式就是二值信号量。即初始值为1的信号量,可以作为互斥体。Semaphore可以用作数据库连接池。

acquire()方法表示获取一个许可,如果没有,则一直阻塞直到有许可。acquire(int)表示获取多个(int)的许可

release()方法表示释放一个许可。release(int) 表示释放多个(int)许可

 

package simple;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Semaphore;

public class BoundedHashSet {
	private final Set set;
	private final Semaphore sem;
	
	public BoundedHashSet(int bound){
		this.set = Collections.synchronizedSet(new HashSet());
		sem = new Semaphore(bound);
	}
	public boolean add(Object o) throws InterruptedException{
		sem.acquire();
		boolean wasAdded = false;
		try{
			wasAdded = set.add(o);
		}finally{
				sem.release();
		}
		return wasAdded;
	}
	public boolean remove(Object o) throws InterruptedException{
		sem.acquire();
		boolean wasRemoved = set.remove(o);
		if(wasRemoved){
			sem.release();
		}
		return wasRemoved;
	}
	public static void main(String []args) throws InterruptedException{
		int n=0;///n=1,2分别有不同的输出,可以观察其中的变化
		BoundedHashSet bs = new BoundedHashSet(n);
		if(bs.remove("213")){
			System.out.println("object has been removed");
		}else{
			System.out.println("waiting .........");
		}
		System.out.println("remove "+bs.set);
		if(bs.add("213")){
			System.out.println("add successful");
		}else{
			System.out.println("waiting for add ........");
		}
		System.out.println("add:"+bs.set);
		if(bs.remove("213")){
			System.out.println("object has been removed");
		}else{
			System.out.println("waiting .........");
		}
		System.out.println("remove after add :"+bs.set);
	}

}

栅栏(Barrier):它能阻塞一组线程知道某个事件发生,与闭锁类似。栅栏与闭锁的区别在于,所有线程必须到达栅栏位置,才能继续执行。闭锁用于等待事件发生,栅栏用于等待其他线程。CyclicBarrier和Exchange

CyclicBarrier:可以使一组线程反复的在栅栏位置汇聚。一组线程在某个时间点达到一致。例如一些迭代算法,每一轮都依赖上一轮的结果(每一轮的所有计算都执行完毕才能进入下一轮步骤)。

eg:f(n) = a(n-1) + b(n-1); 其中a(n) 和b(n)耗时计算而且可以并行计算。就可以采用CyclicBarrier

CyclicBarrier的一些方法如图

 

package simple;

import java.util.concurrent.*;

/**
 * CellularAutomata
 *
 * Coordinating computation in a cellular automaton with CyclicBarrier
 *
 * @author Brian Goetz and Tim Peierls
 */
public class CellularAutomata {
    private final Board mainBoard;
    private final CyclicBarrier barrier;
    private final Worker[] workers;

    public CellularAutomata(Board board) {
        this.mainBoard = board;
        int count = Runtime.getRuntime().availableProcessors();
        this.barrier = new CyclicBarrier(count,
                new Runnable() {
                    public void run() {
                        mainBoard.commitNewValues();
                    }});
        this.workers = new Worker[count];
        for (int i = 0; i < count; i++)
            workers[i] = new Worker(mainBoard.getSubBoard(count, i));
    }

    private class Worker implements Runnable {
        private final Board board;

        public Worker(Board board) { this.board = board; }
        public void run() {
            while (!board.hasConverged()) {
                for (int x = 0; x < board.getMaxX(); x++)
                    for (int y = 0; y < board.getMaxY(); y++)
                        board.setNewValue(x, y, computeValue(x, y));
                try {
                    barrier.await();
                } catch (InterruptedException ex) {
                    return;
                } catch (BrokenBarrierException ex) {
                    return;
                }
            }
        }

        private int computeValue(int x, int y) {
            // Compute the new value that goes in (x,y)
            return 0;
        }
    }

    public void start() {
        for (int i = 0; i < workers.length; i++)
            new Thread(workers[i]).start();
        mainBoard.waitForConvergence();
    }

    interface Board {
        int getMaxX();
        int getMaxY();
        int getValue(int x, int y);
        int setNewValue(int x, int y, int value);
        void commitNewValues();
        boolean hasConverged();
        void waitForConvergence();
        Board getSubBoard(int numPartitions, int index);
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值