Four components of Java concurrency


title: Four components of
JUCdate: 2018-4-3 21:18:40
categories:
- JUC
tags:
- JUC
- concurrent processing

- Source code analysis

CyclicBarrier

It allows a group of threads to wait for each other until some common barrier point is reached. CyclicBarrier is useful in programs involving a set of fixed-size threads that must wait for each other from time to time. Because the barrier can be reused after releasing the waiting thread, it is called a cyclic barrier.
Two constructs are provided:

 public CyclicBarrier(int parties) {
        this(parties, null);
    }
 ``` 
1. CyclicBarrier(int parties):创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,但它不会在启动 barrier 时执行预定义的操作。
```java
 public CyclicBarrier(int parties, Runnable barrierAction) {
        if (parties <= 0) throw new IllegalArgumentException();
        this.parties = parties;
        this.count = parties;
        this.barrierCommand = barrierAction;
    }
 ```
2. CyclicBarrier(int parties, Runnable barrierAction) :创建一个新的 CyclicBarrier,它将在给定数量的参与者(线程)处于等待状态时启动,并在启动 barrier 时执行给定的屏障操作,该操作由最后一个进入 barrier 的线程执行。





<div class="se-preview-section-delimiter"></div>

### await()




<div class="se-preview-section-delimiter"></div>

```java
public int await() throws InterruptedException, BrokenBarrierException {
    try {
        return dowait(false, 0L);
    } catch (TimeoutException toe) {
        throw new Error(toe); // cannot happen
    }
}

Call dowait() internally

private int dowait(boolean timed, long nanos)
            throws InterruptedException, BrokenBarrierException,
            TimeoutException {
        //获取锁
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            //分代
            final Generation g = generation;

            //当前generation“已损坏”,抛出BrokenBarrierException异常
            //抛出该异常一般都是某个线程在等待某个处于“断开”状态的CyclicBarrie
            if (g.broken)
                //当某个线程试图等待处于断开状态的 barrier 时,或者 barrier 进入断开状态而线程处于等待状态时,抛出该异常
                throw new BrokenBarrierException();

            //如果线程中断,终止CyclicBarrier
            if (Thread.interrupted()) {
                breakBarrier();
                throw new InterruptedException();
            }

            //进来一个线程 count - 1
            int index = --count;
            //count == 0 表示所有线程均已到位,触发Runnable任务
            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();
                }
            }


            for (;;) {
                try {
                    //如果不是超时等待,则调用Condition.await()方法等待
                    if (!timed)
                        trip.await();
                    else if (nanos > 0L)
                        //超时等待,调用Condition.awaitNanos()方法等待
                        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();

                //generation已经更新,返回index
                if (g != generation)
                    return index;

                //“超时等待”,并且时间已到,终止CyclicBarrier,并抛出异常
                if (timed && nanos <= 0L) {
                    breakBarrier();
                    throw new TimeoutException();
                }
            }
        } finally {
            //释放锁
            lock.unlock();
        }
    }

The main logic of await() here is that if the secondary thread is not the last to arrive, it is in a waiting state:
1. When the last thread arrives, index = 0;
2. Timeout;
3. Some other thread interrupts the current thread
4. Some other thread interrupts another waiting thread
5. Some other thread is waiting for the barrier to time out
6. Some other thread calls the reset() method on this barrier. The reset() method is used to reset the barrier to its initial state.

In CyclicBarrier, the same batch of threads belong to the same generation. When parties threads reach the barrier, the generation will be updated. Among them, broken identifies whether the current CyclicBarrier has been in the interrupted state.
Sample code, meeting protocol:

import java.util.concurrent.CyclicBarrier;

/**
* @author 作者 : coderlong
* @version 创建时间:2018年4月1日 下午10:06:51
* 类说明: 
*/
public class CyclicbarrierTest {
    private static CyclicBarrier cyclicBarrier;
    static class CyclicBarrierThread extends Thread {
        @Override
        public void run() {
            // TODO Auto-generated method stub
            System.out.println("一个成员到达");
            try {
                cyclicBarrier.await(); // 等待
            } catch (Exception e) {
                // TODO: handle exception
            }
        }
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        cyclicBarrier = new CyclicBarrier(10, new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                System.out.println("人都到齐了,开会!");
            }
        });
        for (int i = 0; i < 10; i++) {
            new CyclicBarrierThread().start();
        }
    }

}
一个成员到达
一个成员到达
一个成员到达
一个成员到达
一个成员到达
一个成员到达
一个成员到达
一个成员到达
一个成员到达
一个成员到达
人都到齐了,开会!

CountDownLatch

What CountDownLatch describes is "it allows one or more threads to wait until a set of operations that are being performed in other threads have been completed".
Textbook - "Initialize CountDownLatch with the given count. Since the countDown() method is called, the await method will block until the current count reaches zero. After that, all waiting threads are released and all subsequent calls to await return immediately. This happens only once - the count cannot be reset. If you need to reset the count, consider using a CyclicBarrier.

gouzaofangfa

public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }

The sync here is the famous AQS synchronizer mentioned earlier, so it is necessary to learn AQS well.

private static final class Sync extends AbstractQueuedSynchronizer {
    private static final long serialVersionUID = 4982264981922014374L;

    Sync(int count) {
        setState(count);
    }

    //获取同步状态
    int getCount() {
        return getState();
    }

    //获取同步状态
    protected int tryAcquireShared(int acquires) {
        return (getState() == 0) ? 1 : -1;
    }

    //释放同步状态
    protected boolean tryReleaseShared(int releases) {
        for (;;) {
            int c = getState();
            if (c == 0)
                return false;
            int nextc = c-1;
            if (compareAndSetState(c, nextc))
                return nextc == 0;
        }
    }
}

The await() method makes the current thread wait until the counter reaches 0, unless an interruption occurs

public void await() throws InterruptedException {
    sync.acquireSharedInterruptibly(1);
}

AcquireSharedInterruptibly(int arg) that calls sync internally

public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    }

sync overrides tryAcquireShared(int arg)

protected int tryAcquireShared(int acquires) {
    return (getState() == 0) ? 1 : -1;
}

The CAS method getState() gets the synchronization state. If the counter value is not equal to 0, it will call doAcquireSharedInterruptibly(int arg), which is a spin method and will try to get the synchronization state all the time.

private void doAcquireSharedInterruptibly(int arg)
        throws InterruptedException {
    final Node node = addWaiter(Node.SHARED);
    boolean failed = true;
    try {
        for (;;) {
            final Node p = node.predecessor();
            if (p == head) {
                /**
                 * 对于CountDownLatch而言,如果计数器值不等于0,那么r 会一直小于0
                 */
                int r = tryAcquireShared(arg);
                if (r >= 0) {
                    setHeadAndPropagate(node, r);
                    p.next = null; // help GC
                    failed = false;
                    return;
                }
            }
            //等待
            if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                throw new InterruptedException();
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

countDown()

CountDownLatch provides the countDown() method to decrement the count of the latch and release all waiting threads if the count reaches zero.

sample code, meeting

import java.util.concurrent.CountDownLatch;

/**
* @author 作者 : coderlong
* @version 创建时间:2018年4月1日 下午10:26:19
* 类说明: 
*/
public class CountDownLatchTest {
    private static CountDownLatch countDownLatch;

    static class Bossthread extends Thread {
        @Override
        public void run() {
            // TODO Auto-generated method stub
            System.out.println("老板在等待,本次会议需要" + countDownLatch.getCount() + "位员工");
            try {
                countDownLatch.await();
            } catch (Exception e) {
                // TODO: handle exception
            }
            System.out.println("所有员工到达,开始开会");
        }
    }
    //员工到达会议室
    static class EmpleoyeeThread  extends Thread{
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + ",到达会议室....");
            //员工到达会议室 count - 1
            countDownLatch.countDown();
        }
    }


    public static void main(String[] args) {
        // TODO Auto-generated method stub
        countDownLatch = new CountDownLatch(5);
        new Bossthread().start();
        for (int i = 0; i < 5; i++) {
            new EmpleoyeeThread().start();
        }
    }

}

Semaphore

Semaphore is a counter that controls access to multiple shared resources. Like CountDownLatch, it is essentially a "shared lock".
Semaphore provides two constructors:
1. Semaphore(int permits) : Creates a Semaphore with a given number of permits and an unfair fairness setting.
2. Semaphore(int permits, boolean fair) : Creates a Semaphore with the given number of permits and the given fairness settings.
So the internal sync is divided into fair and unfair.
Of course, Semaphore chooses unfair locks by default. Most of the time Java is unfair by default.
When the semaphore Semaphore = 1, it can be used as a mutex.
semaphore acquisition

public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

Call acquireSharedInterruptibly(int arg) of AQS, which gets the synchronization state in shared mode:

public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    }

The above method is generally delivered to subclasses to complete, and it is fair and unfair:

protected int tryAcquireShared(int acquires) {
    for (;;) {
        //判断该线程是否位于CLH队列的列头
        if (hasQueuedPredecessors())
            return -1;
        //获取当前的信号量许可
        int available = getState();

        //设置“获得acquires个信号量许可之后,剩余的信号量许可数”
        int remaining = available - acquires;

        //CAS设置信号量
        if (remaining < 0 ||
                compareAndSetState(available, remaining))
            return remaining;
    }
}

unfair

final int nonfairTryAcquireShared(int acquires) {
    for (;;) {
        int available = getState();
        int remaining = available - acquires;
        if (remaining < 0 ||
            compareAndSetState(available, remaining))
            return remaining;
    }
}

It's OK to release it after use. Of course, it is still handed over to the internal AQS to achieve

Exchanger

Well, I don't quite understand this.
The API says this:
A synchronization point for threads that can pair and swap elements in a pair. Each thread presents a method on the entry to the exchange method, matches up with the partner thread, and receives its partner's object on return. Exchanger might be seen as a bidirectional form of SynchronousQueue. Exchanger may be useful in applications such as genetic algorithms and pipeline design. Forgive my algorithm scum, what kind of genetic algorithm, I have only heard of it, and I have never written it.
You can see the analysis of this great god .
The four major components, let's go here, kill my N brain cells, but using the concurrent structure that comes with JUC has many benefits, let's experience it for yourself.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326483873&siteId=291194637