Java JUC 3 -AQS同步组件

上一节 Java JUC 2 -AQS

AQS同步组件

  1. CountDownLatch
    维护一个计数器State,每调用countdown计数器减1,当调用await时,会将当前线程放到阻塞队列中并挂起,只有当state为0时,才会唤醒阻塞队列中的线程(也就是移到同步队列),该线程才会执行。
    当某个计算需要等待另一个应用的完成时使用,用法:
public static void main(String[] args) throws InterruptedException {
	CountDownLatch latch = new CountDownLatch(20);
	ExecutorService service = Executors.newCachedThreadPool();
	for (int i = 0; i < threadCount; i++) {
		final int threadNum = i;
		service.execute(() -> {
		test1(threadNum);
		// 在子线程完成后 countDown
		latch.countDown();
	});
	}
	latch.await(); // 会一直等待,只有当上面20个线程执行完成后,test2才会被执行
	// latch.await(20,TimeUnit.SECONDS); 可以设置超时时间
	test2();
	}
  1. Semaphore
    控制同时访问的个数,用于有限资源的访问,比如数据库
private static void test3(ExecutorService service) {
	Semaphore semaphore = new Semaphore(20);
	for (int i = 0; i < threadCount; i++) {
		final int threadNum = i;
		service.execute(() -> {
		try {
			semaphore.tryAcquire();// 尝试获取许可
			// semaphore.tryAcquire(2);//尝试获取3个许可
			// semaphore.tryAcquire(1, TimeUnit.SECONDS);// 尝试获取许可,试图等待1s
			// semaphore.acquire(); 获取许可
			// semaphore.acquire(3);// 获取许可 可以获取一个,也可以获取多个
			test1(threadNum);
			semaphore.release(3);// 释放许可 ,可以释放一个或多个
		} catch (InterruptedException e) {
		e.printStackTrace();
	}
});
}
}
  1. CyclicBarrier
    栅栏:允许一组线程相互等待,当各自都准备就绪后,才各自向下继续执行,如赛跑。线程调用await进入等待,计数器减一,当计数器为0时,则会被唤醒。线程释放后计数器可以循环使用
    与CountDownLatch很相似,都是通过计数器实现 区别:
    CountDownLatch的计数是递减的,并且是单次使用;
static CyclicBarrier cyclicBarrier = new CyclicBarrier(waitSize);
public static void main(String[] args) throws InterruptedException {
	ExecutorService service = Executors.newCachedThreadPool();
	for (int i = 0; i < threadSize; i++) {
		Thread.sleep(1000);
		final int threadNum = i;
		service.execute(()->{
		try {
			test1(threadNum);
		} catch (Exception e) {
		e.printStackTrace();
	}
	});
	}
	service.shutdown();
}
private static void test1(int threadNum) {
System.out.println(threadNum + " 线程 准备就绪 。。。");
try {
	Thread.sleep(1000);
	cyclicBarrier.await();
// 定时
// cyclicBarrier.await(10,TimeUnit.SECONDS);
} catch (Exception e) {
}
System.out.println(threadNum + " 线程 发车 。。。");
}
// 可以指定一个 runrable,它会优先执行
static CyclicBarrier cyclicBarrier2 = new CyclicBarrier(threadSize,()->{
System.out.println("先执行");
});
  1. ReentrantLook
    实现:是一种自旋锁,通过循环调用cas来实现加锁,性能比较好也是因为避免了使线程进入阻塞态。
    在这里插入图片描述
    使用:
/**
* 声明锁的实例
*/
static ReentrantLock reentrantLock = new ReentrantLock();
// 设置为公平锁
//static ReentrantLock reentrantLock = new ReentrantLock(true);

private static void test1() {
// 加锁
reentrantLock.lock();
try {
	// 在调用时,只有它是空闲的,才能获取锁
	reentrantLock.tryLock();
	// 在给定时间内,它是空闲的或者没有别其他线程所中断,则获取
	reentrantLock.tryLock(100, TimeUnit.SECONDS);
	//如果当前线程没有被中断,则获取锁定
	reentrantLock.lockInterruptibly();
	// 查询此锁是否由任何线程持有
	reentrantLock.isLocked();
	//查询当前线程是否持有此锁定。
	reentrantLock.isHeldByCurrentThread();
	// 是否是公平锁
	reentrantLock.isFair();
	//其他方法不再一一举例
	} catch (InterruptedException e) {
		e.printStackTrace();
	} finally {
	//释放锁
	reentrantLock.unlock();
}
}
  1. ReentrantReadWriteLock
    适用于读多写少的场景,没有任何读锁的时候才能获取写锁,悲观读取(当读取过多时,写可能遭遇饥饿)
    用例:
public class LockExample2 {

private final Map<String, String> map = new TreeMap<>();
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

private final Lock readLock = lock.readLock();
private final Lock writeLock = lock.writeLock();

public String get(String key){
readLock.lock();
try {
return map.get(key);
}finally {
readLock.unlock();
}
}
public void put(String key,String value){
writeLock.lock();
try {
map.put(key,value);
}finally {
writeLock.unlock();
}
}
}
  1. StampedLock
    支持写、读和乐观读
    状态由版本和模式两部分组成,锁获取方法返回一个数字作为票据,释放锁时,需要传入该值

BlockingQueue阻塞队列

BlockingQueue 会让服务线程在队列为空时,进行等待,当有新的消息进入队列后,自动唤醒线程。提供四套使用方法
在这里插入图片描述
1. ArrayBlockingQueue:
初始化时需要指定大小,并且不能改变,先进先出原则
2. LinkedBlockingQueue:
大小可选,如果指定就是固定的,不指定就是不固定的,先进先出
3. DelayQueqe:
元素需要实现delayt接口,有序的,一般按元素过期时间的优先级排序,由于定时关闭连接,超时处理等
4. PriorityBlockingQueue:
带优先级的阻塞队列,没有边界,有排序规则,允许插入null,插入的对象必须实现 compable 接口
5. SynchronousQueue:
仅允许容纳一个元素,同步队列

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值