概述:
CountDownLatch(计数器)是一个用于多线程同步的 Java 工具。它允许一个或多个线程等待,直到其他线程完成任务或是事件的发生。CountDownLatch 通常用于协调多个线程之间的同步,以便一个线程等待另一个线程完成某项任务后再继续执行。
CountDownLatch 本质上是一个计数器,用于记录需要等待的线程数量。当一个线程完成任务时,它会通知 CountDownLatch 计数器减一。当计数器的值减为零时,等待的线程将被释放,可以继续执行下面的任务。
使用 CountDownLatch 可以通过调用 await() 方法来阻塞当前线程,等待其他线程完成任务。当需要等待的线程数量减少时,可以调用 countDown() 方法通知 CountDownLatch 计数器减一。当计数器的值减为零时,等待的线程将被释放。
要使用CountDownLatch,首先需要创建一个CountDownLatch对象,然后在线程中调用countDown()方法来通知CountDownLatch计数器减1。当计数器的值变为0时,等待在CountDownLatch上的线程就会被唤醒。
CountDownLatch latch = new CountDownLatch(1);
// ...
latch.await(); // 等待计数降到0
使用示例1
mport java.util.concurrent.CountDownLatch;
public class CountDownLatchExample {
public static void main(String[] args) throws InterruptedException {
int countDownValue = 3;
CountDownLatch latch = new CountDownLatch(countDownValue);
// 创建三个线程来执行任务
Thread thread1 = new Thread(() -> {
latch.countDown(); // 通知计数器减1
System.out.println("Thread 1 完成");
});
Thread thread2 = new Thread(() -> {
latch.countDown(); // 通知计数器减1
System.out.println("Thread 2 完成");
});
Thread thread3 = new Thread(() -> {
latch.countDown(); // 通知计数器减1
System.out.println("Thread 3 完成");
});
// 启动线程
thread1.start();
thread2.start();
thread3.start();
// 等待所有线程执行完毕
latch.await(); // 在这里等待,直到计数器的值变为0
// 所有线程已经执行完毕,继续执行下面的任务
System.out.println("所有 threads 完成");
}
}
在上面的示例中,我们创建了一个CountDownLatch对象,并将其初始化为3。然后我们创建了三个线程来执行任务,并在每个线程中调用countDown()方法来通知计数器减1。最后,在主线程中,我们使用await()方法等待所有线程执行完毕,然后继续执行下面的任务。
使用示例2
使用线程池生成100*300个Redis 全局ID
@SpringBootTest
@RunWith(SpringRunner.class)
public class AppTest {
@Resource
private RedisWorker redisWorker;
private ExecutorService es = Executors.newFixedThreadPool(100);
@Test
public void testNextId() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(300);
Runnable task = () -> {
for (int j = 0; j < 100; j++) {
System.out.println("id========" + redisWorker.nextId("order"));
}
latch.countDown(); //通知计数器减1
};
long begin = System.currentTimeMillis();
for (int i = 0; i < 300; i++) {
es.submit(task);
}
latch.wait(); // 在这里等待,直到计数器的值变为0
long end = System.currentTimeMillis();
//记录完成时间
System.out.println("time===" + (end - begin));
}
}
@Component
public class RedisWorker {
//开始时间错
private final static long BEGIN_TIMESTAMP = 1640995200l;
//序列号位数
private final static long COUNT_BITS = 32;
@Autowired
private StringRedisTemplate redisTemplate;
public long nextId(String keyPre){
// 1 生成时间错
LocalDateTime now = LocalDateTime.now();
long nowSecond = now.toEpochSecond(ZoneOffset.UTC);
long timestamp = nowSecond - BEGIN_TIMESTAMP;
// 2 生成序列号
// 2.1 获取date,便于获得一天的订单
String date = now.format(DateTimeFormatter.ofPattern("yyyyMmdd"));
// 2.2 自增长
Long count = redisTemplate.opsForValue().increment("icr:" + keyPre + ":" + date);
// 3 拼接并返回
return timestamp << COUNT_BITS | count;
}
}
源码下载:
https://gitee.com/charlinchenlin/koo-erp