同步工具类

来源:互联网 发布:iphone网络锁解锁软件 编辑:程序博客网 时间:2024/06/13 10:49

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







原创粉丝点击