同步工具类--闭锁、信号量、栅栏的总结

来源:互联网 发布:外贸数据 编辑:程序博客网 时间:2024/05/16 01:51

      闭锁用于一组线程等待(阻塞)一个外部事件的发生,这个事件发生之前这些线程阻塞,等待控制线程打开闭锁,然后这些线程同时开始执行。闭锁强调的是阻塞后的同时开始;栅栏则是一组线程相互等待,直到所有线程都到达某一点时才打开栅栏,然后线程可以继续执行,也就是说控制线程先设置一个时间点,然后这些线程各自执行,执行完等待(阻塞),直到这组线程中的所有线程执行完,然后控制线程栅栏打开,这些线程同时继续执行。栅栏强调的是各自执行完后的相互等待以及继续执行。信号量根据一个计数器控制一个结果的数量,条件满足情况下才能进行增加和移除操作,否则进行操作的线程阻塞。

工具

作用

主要方法

闭锁

(CountDownLatch)

类似于门。门初始是关闭的,试图进门的线程挂起等待开门。当负责开门进程将门打开后,所有等待线程被唤醒。

门一旦打开就不能再关闭了。

CountDownLatch(int n):指定闭锁计数器

await() :挂起等待闭锁计数器为0

countDown():闭锁计数器减1

栅栏

(CyclicBarrier)

和闭锁有类似之处。闭锁是等待“开门”事件;栅栏是等待其他线程。例如有N个线程视图通过栅栏,此时先到的要等待,直到所有线程到到达后,栅栏开启,所有等待线程被唤醒通过栅栏。

CyclicBarrier(int n):需要等待的线程数量

await():挂起等待达到线程数量

信号量

(Semaphore)

和锁的作用类似。区别是锁只允许被一个线程获取,但是信号量可以设置资源数量。当没有可用资源时,才被挂起等待。

Semaphore(int n):指定初始的资源数量

acquire():试图获取资源。当没有可用资源时挂起

release():释放一个资源

场景对比:

l  闭锁场景:几个人相约去公园游玩,在家做好准备,约定在某一时刻同时出发去公园,准备工作进行的快的不能提前出门,到点出门。

l  栅栏场景:几个人相约去公园游玩,几个人去到公园门口,要等全部到达公园门口后才一起进入公园。

l  信号量场景:几个人相约去公园游玩,等大家都到公园后,发现来的太迟了,公园游客饱和,公园限制入场游客的数量。游客在门口等待,出来一人,再进入一人,只能一个一个进入。


CountDownLatch:


public class TestHarness{
    public long timeTasks(int nThreads, final Runnable task) throws InterruptedException{
        final CountDownLatch startGate = new CountDownLatch(1);//全部线程开始的闭锁
        final CountDownLatch endGate = new CountDownLatch(nThread);//全部线程结束的闭锁
        for(int i = 0 ; i < nThreads ; i++){
            Thread t = new Thread(){
                public void run(){
                    try{
                        startGate.await();//所有的线程都在这里等待闭锁打开
                        try{
                            task.run();//实际要调用的方法
                        }finally{
                            endGate.countDown(); //每一个线程执行完毕,调用countDown()方法,直到全部的线程(nThreads个)执行完毕,闭锁打开
                        }
                    }catch(InterruptedException e){}
                }
            };
            t.start(); //t.start()不会立即开始执行task.run()方法,线程一开始执行startGate.await();会等待闭锁startGate打开
        }
        long start = System.nanoTime();//记录开始时间
        startGate.countDown();//闭锁startGate初始化为1,执行一次countDown()方法,闭锁就打开了,所有的线程可以继续执行
        endGate.await();//当前线程在这里等待所有的线程执行完毕
        long end = System.nonaTIme();//记录结束时间
        return end - start;
    }
}


semaphore :

public class BoundedHashSet<T>{
        private final Set<T> set;
        private final Semaphore sem;
        //构造方法,初始化边界
        public BoundedHashSet(int bound){
            this.set = Collections.synchronizedSet(new HashSet<T>());
            sem = new Semaphore(bound);//初始化许可集的大小,即该有界阻塞队列的大小
        }
 
        public boolean add(T o) throws InterruptedException{
            sem.acquire();//添加元素时获取一个许可,如果剩余许可为0,则说明此有界阻塞队列已满
            boolean wasAdded = false; //返回值,默认为添加元素失败。
            try{
                wasAdded=set.add(o);//向队列中添加元素,如果成功,则返回成功
                return wasAdded;
            }finally{
                if(!wasAdded) sem.release(); //如果添加失败,把方法一开始获取的许可释放掉
            }
        }
        
        public boolean remove (Object o){
            boolean wasRemoved = set.remove(o);
            if(wasRemoved) sem.release();//如果删除成功,则释放一个许可
            return wasRemoved;
        }
    }


barrier:

class Solver {
   final int N;
   final float[][] data;
   final CyclicBarrier barrier;
   
   class Worker implements Runnable {
     int myRow;
     Worker(int row) { myRow = row; }
     public void run() {
       while (!done()) {
         processRow(myRow); //每一个线程负责处理一行数据


         try {
           barrier.await(); //处理完行数据之后在这个关卡等待其他线程,当所有的线程都处理完毕,才继续向下执行
         } catch (InterruptedException ex) { 
            return; 
         } catch (BrokenBarrierException ex) { 
            return; 
         }
       }
     }
   }


   public Solver(float[][] matrix) {
     data = matrix;
     N = matrix.length;
     barrier = new CyclicBarrier(N, 
                                 new Runnable() {
                                   public void run() { 
                                     mergeRows(...); //汇总计算的结果语句
                                   }//关卡CyclicBarrier 初始化时参数一为:关卡需要等待的线程的数量n,只有当n个线程全部到达此关卡,才能顺利通过;参数二为:一个关卡行为,当关卡顺利通过之后,在一个子任务线程中执行这个行为。Runnable类型~
                                 });
     for (int i = 0; i < N; ++i) 
       new Thread(new Worker(i)).start(); //每一行一个线程处理,分别启动


     waitUntilDone();
   }
}





0 0
原创粉丝点击