三个并发的常用辅助类:
1、CountDownLatch
可以当做类似一个倒计时计数器来记,一个实例:
老师要等教室里的6个学生都走了才能关门
// 倒计时计数器
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 1; i <= 6; i++) {
new Thread(()->{
System.out.println("第"+Thread.currentThread().getName()+"个学生Go out");
countDownLatch.countDown(); // 减一操作
},String.valueOf(i)).start();
}
countDownLatch.await(); // 等待计数器为0再向下执行
System.out.println("关门");
2、CyclicBarrier
可以当做一个加法计数器来记,一个实例:
当集齐七科龙珠,就可以召唤神龙
CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{
System.out.println("召唤神龙成功!");
});
for (int i = 1; i <= 7; i++) {
final int temp = i; // 解决作用域的问题(lambda表达式里不能直接拿到i)
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"收集了第"+temp+"颗龙珠");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
},String.valueOf(i)).start();}
3、Semaphore
信号量的辅助类,可以当做限流的使用来记(多个线程使用一个共享资源互斥的使用),实例:
抢车位,3个车位,有6辆车来停,保证有序停车
public class Test3 {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3); // 3个车位
for (int i = 1; i <= 6; i++) {
final int temp = i; // 解决作用域的问题(lambda表达式里不能直接拿到i)
new Thread(()->{
try {
semaphore.acquire(); // 得到停车位
System.out.println(Thread.currentThread().getName()+"抢到车位");
TimeUnit.SECONDS.sleep(2); // 停2秒车
System.out.println(Thread.currentThread().getName()+"离开车位");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
semaphore.release(); // 释放
}
},String.valueOf(i)).start();
}
}
}
Semaphore的两个主要方法:
semaphore.acquire()
:获得资源,如果到达峰值,等待至被释放为止;
semaphore.release()
:将当前的信号量释放,然后唤醒等待的线程;
ReadWriteLock
读写锁,更加细粒度的操作,它的写是只允许一条线程去写,而读是允许所有线程都可去读。实例:
5条线程去写入,5条线程去读取,确保写入操作不会被其他线程插队
public class Test1 {
public static void main(String[] args) {
MyCache myCache = new MyCache();
for (int i = 1; i <= 5; i++) { // 只做写入操作
final int temp = i;
new Thread(()->{
myCache.put(temp+"",temp+"");
},String.valueOf(i)).start();
}
for (int i = 1; i <= 5; i++) { // 只做读取操作
final int temp = i;
new Thread(()->{
myCache.get(temp+"");
},String.valueOf(i)).start();
}
}
}
/* 自定义缓存 */
class MyCache {
private volatile Map<String,Object> map = new HashMap<>();
// 读写锁,更加细粒度的操作
private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
// 存(写入操作,只有一条线程能写)
public void put(String key,Object value){
readWriteLock.writeLock().lock(); // 上锁
try {
System.out.println(Thread.currentThread().getName()+"写入"+key);
map.put(key,value);
System.out.println(Thread.currentThread().getName()+"写入OK");
} catch (Exception e) {
e.printStackTrace();
} finally {
readWriteLock.writeLock().unlock(); // 解锁
}
}
// 取(读取操作,所有线程都能读)
public void get(String key){
readWriteLock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName()+"读取"+key);
Object o = map.get(key);
System.out.println(Thread.currentThread().getName()+"读取OK");
} catch (Exception e) {
e.printStackTrace();
} finally {
readWriteLock.readLock().unlock();
}
}
}
BlockQueue
阻塞队列的四组API:
超时等待里的参数详情:
offer(value,时间数,时间类型)
poll(时间数,时间类型)