首先看下下面这段代码:
package com.mmall.concurrency.example.atomic;
import com.mmall.concurrency.annoations.ThreadSafe;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicLong;
@Slf4j
@ThreadSafe
public class AtomicExample2 {
// 请求总数
public static int clientTotal = 5000;
// 同时并发执行的线程数
public static int threadTotal = 200;
public static AtomicLong count = new AtomicLong(0);
public static void main(String[] args) throws Exception {
ExecutorService executorService = Executors.newCachedThreadPool();
final Semaphore semaphore = new Semaphore(threadTotal);
final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
for (int i = 0; i < clientTotal; i++) {
executorService.execute(() -> {
try {
semaphore.acquire();
add();
semaphore.release();
} catch (Exception e) {
}
countDownLatch.countDown();
});
}
countDownLatch.await();
executorService.shutdown();
System.out.println("count:{}" + count.get());
}
private static void add() {
count.incrementAndGet();
// count.getAndIncrement();
}
}
1、代码中使用了final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);来初始化CountDownLatch对象
2、通过查看CountDownLatch的该构造方法:主要是对CountDownLatch类中的变量sync进行了初始化的赋值。
3、在使用CountDownLatch的时候,使用的是countDownLatch.countDown();方法,而countDown方法的源码如下:
其releaseShared方法明显是要将sync变量进行减1的操作,但是为了保证原子性,底层源码使用了如下:首先这里使用的是一个死循环(也就是为什么说耗性能的原因),循环中不断获取head的值,而最终break的条件是h==head。所以看其中逻辑,里面的compareAndSetWaitStatus,这里就是很有名的CAS的全称了
此时再看看CountDownLatch的概念:
CountDownLatch是一个同步工具类,用来协调多个线程之间的同步,或者说起到线程之间的通信(而不是用作互斥的作用)。
CountDownLatch能够使一个线程在等待另外一些线程完成各自工作之后,再继续执行。使用一个计数器进行实现。计数器初始值为线程的数量。当每一个线程完成自己任务后,计数器的值就会减一。当计数器的值为0时,表示所有的线程都已经完成了任务,然后在CountDownLatch上等待的线程就可以恢复执行任务。