JUC必知必会案例
CountDownLatch
CountDownLatch(闭锁)是一个同步协助类,允许一个或多个线程等待,直到其他线程完成操作。CountDownLatch使用给定的计数值(count)初始化。await方法会阻塞直到当前的计数值(count)由于countDown方法的调用达到0,count为0之后所有等待的线程都会被释放,并且随后对await方法的调用都会立即返回。
package com.company.juccase;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
/**
* CountDownLatch使用案例——多线程聚合统计指标
* @Author: Alan
* @Date: 2022/11/20 21:19
*/
public class CountDownLatchDemo {
//用于聚合所有的统计指标
private static Map<String,Object> map = new ConcurrentHashMap();
//创建计数器,这里需要统计4个指标
private static CountDownLatch countDownLatch = new CountDownLatch(4);
public static void main(String[] args) {
//记录开始时间
long startTime = System.currentTimeMillis();
Thread countUserThread = new Thread(() -> {
try {
System.out.println("正在统计新增用户数量");
Thread.sleep(3000);//任务执行需要3秒
map.put("userNumber", 100);//保存结果值
System.out.println("统计新增用户数量完毕");
countDownLatch.countDown();//标记已经完成一个任务
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread countOrderThread = new Thread(() -> {
try {
System.out.println("正在统计订单数量");
Thread.sleep(3000);//任务执行需要3秒
map.put("countOrder", 20);//保存结果值
System.out.println("统计订单数量完毕");
countDownLatch.countDown();//标记已经完成一个任务
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread countGoodsThread = new Thread(() -> {
try {
System.out.println("正在商品销量");
Thread.sleep(3000);//任务执行需要3秒
map.put("countGoods", 300);//保存结果值
System.out.println("统计商品销量完毕");
countDownLatch.countDown();//标记已经完成一个任务
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread countMoneyThread = new Thread(() -> {
try {
System.out.println("正在总销售额");
Thread.sleep(3000);//任务执行需要3秒
map.put("countMoney", 40000);//保存结果值
System.out.println("统计销售额完毕");
countDownLatch.countDown();//标记已经完成一个任务
} catch (InterruptedException e) {
e.printStackTrace();
}
});
//启动子线程执行任务
countUserThread.start();
countGoodsThread.start();
countOrderThread.start();
countMoneyThread.start();
try {
//主线程等待所有统计指标执行完毕
countDownLatch.await();
long endTime = System.currentTimeMillis();//记录结束时间
System.out.println("------统计指标全部完成--------");
System.out.println("统计结果为:" + map);
System.out.println("任务总执行时间为" + (endTime - startTime) + "ms");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
ReentrantLock
ReentrantLock是一种基于AQS框架的应用实现,是JDK中的一种线程并发访问的同步手段,它的功能类似于synchronized是一种互斥锁,可以保证线程安全。
package com.company.juccase;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* ReentrantLock使用案例——使用ReentrantLock加锁
* @Author: Alan
* @Date: 2022/11/20 01:38
*/
public class ReentrantLockDemo {
private static int sum=0;
private static Lock lock=new ReentrantLock();
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
// 获取锁
lock.lock();
try {
new Thread(()->{
for (int j = 0; j < 1000; j++) {
sum++;
}
}).start();
}finally {
// 在finally代码块中释放锁
lock.unlock();
}
}
// 保证所有线程执行完毕
Thread.sleep(3000);
System.out.println(sum);
}
}
Semaphore
信号量
package com.company.juccase;
import java.util.concurrent.Semaphore;
/**
* Semaphore使用案例——限流
* @Author: Alan
* @Date: 2022/11/20 21:28
*/
public class SemaphoreDemo {
public static void main(String[] args) {
// 声明3个窗口 state: 资源数
Semaphore windows = new Semaphore(3);
for (int i = 0; i < 5; i++) {
new Thread(()->{
try {
// 占用窗口 加锁
windows.acquire();
System.out.println(Thread.currentThread().getName() + ": 开始买票");
//模拟买票流程
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName() + ": 购票成功");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 释放窗口
windows.release();
}
}).start();
}
}
}