The java JUC assembly (Semaphore, CountDownLatch, CyclicBarrier)

1 Introduction

Operation Semaphore, CountDownLatch, CyclicBarrier three tools are for concurrency control are based on the underlying AQS to achieve;

  • Semaphore (Semaphore): Provides a competitive resource processing tool when the system has enough things semaphore, a thread can perform an operation to acquire a semaphore when the semaphore resources After use, you must wait for the release of resources subsequent threads ( competition for resources) to be able to perform;
  • A CountDownLatch (blocking): can be understood as a switch, latch created, you can specify the number of dependencies a locking opening only when ready to meet the conditions of resources, the locking opening, the threads may execute a subsequent task;
  • CyclicBarrier (fence): When all dependent fence thread execution to key nodes, we need to wait for other threads reach the barrier point, or can not continue, all the threads reach the critical point of the fence, these threads can continue to perform follow-up tasks.

2、Semaphore

Semaphore execution flow diagram of code for use in:

SemaPhore_Flow.png

Its essence is the operating system of PV operation, when sufficient resources and access to resources when the thread execution thread to wait or exit insufficient resources, when resources are released and the thread can acquire the resources to continue to compete;

2.1 source code to achieve:

Semaphore_structure.png

Semaphore class code structure shown above, it can be seen that the interior locking achieve fair and unfair lock, so we can use two different modes to construct Semaphore object instance;

Whether we use a fair and non-fair locks, which will eventually initialization call to the constructor of sync;
Here you can see the inside of the access to resources and to achieve the release of specific resources:


public class Semaphore implements java.io.Serializable {
    abstract static class Sync extends AbstractQueuedSynchronizer{
        //初始化
        Sync(int permits) {
            setState(permits);
        }
    }
    public void acquire(int permits) throws InterruptedException {
        if (permits < 0) throw new IllegalArgumentException();
        sync.acquireSharedInterruptibly(permits);
    }
    public void release() {
        sync.releaseShared(1);
    }
}

sync.acquireSharedInterruptibly (permits) AQS implementation will eventually call for AQS in this simple: If you can get here to the resources, internal returns success, this will be deducted the value of permits, the task continues to execute. Otherwise, the current threads are waiting queue (specific reference AbstractQueuedSynchronizer.acquireSharedInterruptibly ());

3、CountDownLatch

CountDownLatch execution flow diagram of code for use in:

CountDownLatch_Flow.png

3.1 source code implementation

CountDownLatch_structure.png

public class CountDownLatch {

    private static final class Sync extends AbstractQueuedSynchronizer {
        protected int tryAcquireShared(int acquires) {
            return (getState() == 0) ? 1 : -1;
        }
    }
    
    public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }
    
    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }
    
    public void countDown() {
        sync.releaseShared(1);
    }
}

When a thread calls the await () method implemented due tryAcquireShared CountDownLatch.Sync determines whether the state is equal to 0, if not equal, it must wait queue until countDown call sync.releaseShared (1) so that the sync state to the 0 , await thread will continue;

4、CyclicBarrier

CyclicBarrier execution flow diagram of code for use in:

CyclicBarrier_Flow.png

4.1 source code implementation

CyclicBarrier_structure.png

public class CyclicBarrier {

    public int await() throws InterruptedException, BrokenBarrierException {
        try {
            return dowait(false, 0L);
        } catch (TimeoutException toe) {
            throw new Error(toe); // cannot happen
        }
    }
    private static class Generation {
        boolean broken = false;
    }
    private int dowait(boolean timed, long nanos)
        throws InterruptedException, BrokenBarrierException,
               TimeoutException {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            //保存当前generation 副本
            final Generation g = generation;
            //如果当前副本已推出,抛出异常
            if (g.broken)
                throw new BrokenBarrierException();
            //如果当前线程已中断抛出异常
            if (Thread.interrupted()) {
                breakBarrier();
                throw new InterruptedException();
            }

            //计算当前是否所有线程到达“栅栏”
            int index = --count;
            if (index == 0) {  // tripped
                //所有线程到达栅栏
                boolean ranAction = false;
                try {
                    //如果初始化了自定方法,触发
                    final Runnable command = barrierCommand;
                    if (command != null)
                        command.run();
                    ranAction = true;
                    //唤醒所有到达“栅栏”的线程,并跳到下一个新的generation
                    nextGeneration();
                    return 0;
                } finally {
                    if (!ranAction)
                        breakBarrier();
                }
            }

            // loop until tripped, broken, interrupted, or timed out
            //如果还有线程没有到达栅栏
            for (;;) {
                try {
                    //根据设置的等待时间进行等待
                    //里面会调用LockSupport.park(this);
                    //将当前线程放入等待队列中
                    if (!timed)
                        trip.await();
                    else if (nanos > 0L)
                        nanos = trip.awaitNanos(nanos);
                } catch (InterruptedException ie) {
                    //异常处理流程
                    if (g == generation && ! g.broken) {
                        breakBarrier();
                        throw ie;
                    } else {
                        // We're about to finish waiting even if we had not
                        // been interrupted, so this interrupt is deemed to
                        // "belong" to subsequent execution.
                        Thread.currentThread().interrupt();
                    }
                }
                
                if (g.broken)
                    throw new BrokenBarrierException();
                //当前线程geration 不等于实际 geration 正常返回
                if (g != generation)
                    return index;
                //超过等待时间所有线程还未到达“栅栏”,抛出异常
                if (timed && nanos <= 0L) {
                    breakBarrier();
                    throw new TimeoutException();
                }
            }
        } finally {
            lock.unlock();
        }
    }
    //跳到下一个geration操作
    private void nextGeneration() {
        // signal completion of last generation
        trip.signalAll();
        // set up next generation
        count = parties;
        generation = new Generation();
    }
}

CyclicBarrier maintains a counter, and a geration await each call will have to counter a reduction, and produce a new geration, as long as the counter is not zero, all threads are pre-trigger ((Condition) trip) .await (); internal calls LockSupport.park (this); method threads are waiting queue, know all the threads in place, calls trip.signalAll (); wake up all threads while executing a Runnable user-defined policies

Guess you like

Origin www.cnblogs.com/wykCN/p/12153785.html