JUC三大辅助类
一、CountDownLatch:减少计数方法
作用:让一些线程阻塞直到另一些线程完成一系列操作后才被唤醒。
提供的三个方法:
new CountDownLatch(6);
设置计数器为6个线程countDown();
将计数器减1(调用countDown方法的线程不会阻塞)await();
计数器的值>0,线程会阻塞,当计数器的值=0时,因await()方法阻塞的线程会被唤醒,继续执行
import java.util.concurrent.CountDownLatch;
public class CountDownLatchDemo
{
public static void main(String[] args) throws InterruptedException
{
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 1; i <=6; i++) //6个上自习的同学,各自离开教室的时间不一致
{
new Thread(() -> {
System.out.println(Thread.currentThread().getName()+"\t 号同学离开教室");
//线程调用countDown()方法会将计数器减1(调用countDown方法的线程不会阻塞)
countDownLatch.countDown();
}, String.valueOf(i)).start();
}
//线程调用await()方法时,这些线程会阻塞
countDownLatch.await();
//当计数器的值变为0时,因await()方法阻塞的线程会被唤醒,继续执行
System.out.println(Thread.currentThread().getName()+"\t****** 班长关门走人,main线程是班长");
}
}
二、CyclicBarrier:循环栅栏方法
作用:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续执行。
提供的方法:
new CyclicBarrier(int parties, Runnable barrierAction);
构造方法中:需要类实现Runnable接口cyclicBarrier.await();
同步点阻塞
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierDemo
{
private static final int NUMBER = 7;
public static void main(String[] args)
{
//构造器:CyclicBarrier(int parties, Runnable barrierAction)
CyclicBarrier cyclicBarrier = new CyclicBarrier(NUMBER, ()->{System.out.println("*****集齐7颗龙珠就可以召唤神龙");}) ;
for (int i = 1; i <= 7; i++) {
new Thread(() -> {
try {
System.out.println(Thread.currentThread().getName()+"\t 星龙珠被收集 ");
//阻塞点 awaitCurrent >= 7 ? openAwait() : await();
cyclicBarrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}, String.valueOf(i)).start();
}
}
}
三、Semaphore:信号灯
作用:
- 用于多个共享资源的互斥使用
- 用于并发线程数的控制。
提供的方法:
new Semaphore(3);
//模拟3个资源,可申请使用可释放acquire();
申请,当一个线程调用acquire()操作时,它要么通过,成功获取信号量(信号量减1),要么一直等下去,直到有线程释放信号量,或超时release();
释放,使用在finally{}中,会将信号量的值加1,然后唤醒等待的线程
import java.util.Random;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
public class SemaphoreDemo
{
public static void main(String[] args)
{
Semaphore semaphore = new Semaphore(3);//模拟3个停车位
for (int i = 1; i <=6; i++) //模拟6部汽车
{
new Thread(() -> {
try
{
semaphore.acquire();//申请获取资源
System.out.println(Thread.currentThread().getName()+"\t 抢到了车位");
TimeUnit.SECONDS.sleep(new Random().nextInt(5));
System.out.println(Thread.currentThread().getName()+"\t------- 离开");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
//释放资源信号量,唤醒等待线程
semaphore.release();
}
}, String.valueOf(i)).start();
}
}
}
ReadWriteLock:读写锁
- import java.util.concurrent.locks.*;三种锁:
- Condition
- Lock
- ReadWriteLock
作用:多线程同时读写数据时会出现混乱,用读写锁将读写分开,让写分离,读读共享
提供方法:
ReadWriteLock rwLock = new ReentrantReadWriteLock();
实现类构造器- 写锁writeLock:
rwLock.writeLock().lock();
,在finally{}处解锁:rwLock.writeLock().unlock();
- 读锁readLock:
rwLock.readLock().lock();
,在finally{}处解锁:rwLock.readLock().unlock();
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
class MyCache {
private volatile Map<String, Object> map = new HashMap<>();
private ReadWriteLock rwLock = new ReentrantReadWriteLock();
public void put(String key, Object value) {
rwLock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() + "\t 正在写" + key);
//暂停一会儿线程
try {
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
map.put(key, value);
System.out.println(Thread.currentThread().getName() + "\t 写完了" + key);
System.out.println();
} catch (Exception e) {
e.printStackTrace();
} finally {
rwLock.writeLock().unlock();
}
}
public Object get(String key) {
rwLock.readLock().lock();
Object result = null;
try {
System.out.println(Thread.currentThread().getName() + "\t 正在读" + key);
try {
TimeUnit.MILLISECONDS.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
result = map.get(key);
System.out.println(Thread.currentThread().getName() + "\t 读完了" + result);
} catch (Exception e) {
e.printStackTrace();
} finally {
rwLock.readLock().unlock();
}
return result;
}
}
public class ReadWriteLockDemo {
public static void main(String[] args) {
MyCache myCache = new MyCache();
for (int i = 1; i <= 5; i++) {
final int num = i;
new Thread(() -> {
myCache.put(num + "", num + "");
}, String.valueOf(i)).start();
}
for (int i = 1; i <= 5; i++) {
final int num = i;
new Thread(() -> {
myCache.get(num + "");
}, String.valueOf(i)).start();
}
}
}
BlockingQueue:阻塞队列
当队列是空的,从队列中获取元素的操作将会被阻塞
当队列是满的,从队列中添加元素的操作将会被阻塞
-
Collection
- Queue
- BlockingQueue:阻塞队列
- ArrayBlockingQueue:数组结构阻塞队列
- LinkedBlockingQueue:链表结构阻塞队列(大小默认值为Integer.MAX_VALUE)
- SynchronousQueue:单元素阻塞队列
- PriorityBlockingQueue:优先级排序无界阻塞队列
- DelayQueue:优先级延迟无界阻塞队列
- LinkedTransferQueue:链表无界阻塞队列
- LinkedBlockingDeque:链表双向阻塞队列
- BlockingQueue:阻塞队列
- Queue
-
BlockingQueue的方法:
- 创建方法:
BlockingQueue<String> Queue = new ArrayBlockingQueue<>(int initSize);
- 创建方法:
方法类型 | 抛出异常 | 返回特殊值 | 阻塞 | 超时 |
---|---|---|---|---|
插入 | boolean add(e) | boolean offer(e) | void put(e) | boolean offer(e,timeout,timeunit) |
删除 | E remove() | E poll() | E take() | boolean poll(e,timeout,timeunit) |
检查 | E element() | E peek() | / | / |
类型 | 说明 |
---|---|
抛出异常 | 1. 当阻塞队列满时,再往队列里add插入元素 会抛IllegalStateException:Queue full 2. 当阻塞队列空时,再往队列里remove移除元素 会抛NoSuchElementException |
特殊值 | 1. 插入方法,成功ture失败false 2. 删除方法,成功返回出队列的元素,队列里没有就返回null |
一直阻塞 | 1. 当阻塞队列满时,生产者线程继续往队列里put元素, 队列会一直阻塞生产者线程直到put数据or响应中断退出 2. 当阻塞队列空时,消费者线程试图从队列里take元素, 队列会一直阻塞消费者线程直到队列可用 |
超时退出 | 当阻塞队列满时,队列会阻塞生产者线程一定时间,超过限时后生产者线程会退出 |