CountDownLatch和CyclicBarrier都有让多个线程等待同步然后再开始下一步动作的意思,但是CountDownLatch的下一步的动作实施者是主线程,主线程等待其他线程,具有不可重复性;而CyclicBarrier的下一步动作实施者还是“其他线程”本身,线程互相等待,具有往复多次实施动作的特点。
Condition是一种广义上的条件队列,它为线程提供了一种更为灵活的等待/通知模式,Condition是一个接口,它的实现ConditionObject是AQS的一个内部类,Conditon必须配合锁一起使用。condition调用await会释放锁,调用condition.await()、condition.signal()的线程必须已经获取了锁,否则会抛出IllegalMonitorStateException异常.
其作用是设置一个屏障,当到达屏障点的线程达到指定数量时,继续往下执行。用于控制多线程在某一个点同步等待。内部采用共享锁实现。
构造方法:CountDownLatch(int count) count表示需要达到屏障点的线程数量
核心方法:
countDown()线程调用该方法,计数减1,当计数为0,放行
await() 屏障点,使当前线程阻塞,直到count为零时才往下继续执行
缺点:不能重用
CyclicBarrier是一个同步辅助类,它允许一组线程互相等待。
它有两个构造方法:
CyclicBarrier(int parties):创建一个新的CyclicBarrier,拦截线程数为parties
CyclicBarrier(int parties,Runnable barrierAction):创建一个CyclicBarrier,拦截线程数位parties,当所有线程到达屏障点时,执行barrierAction中的动作
核心方法await()
优点:可重用
缺点:不能动态增加计数,也不能动态减少计数
Semaphore资源共享控制器,其作用是控制同一时间内,有多少个线程可以同时访问特定的资源。内部采用共享锁实现。
常用于实现资源池,如数据库连接池,线程池...
以Semaphore为例,其内部维护一组资源,可以通过构造函数指定数目,其它线程在执行的时候,可以通过acquire方法获取资源,有的话,继续执行(使用结束后释放资源),没有资源的话将阻塞直到有其它线程调用release方法释放资源;
构造函数:
Semaphore(int permits):新建一个Semaphore,许可数为permits
Semaphore(int permits, boolean fair):创建一个有permits个许可和给定公平性的Semaphore
核心方法:
acquire() 获取一个许可
acquire(int permits) 获取permits个许可
release() 释放一个许可
release(int permits) 释放permits个许可
作用是使得两个线程之间可以进行数据交换
构造方法:
Exchanger() 创建一个交换器
核心方法:
exchange(E e)执行数据交换,此方法会阻塞,直到有另一个线程和它进行数据交换或者被打断为止
LinkedBlockingQueue
阻塞队列提供了可阻塞的入队和出对操作,如果队列满了,入队操作将阻塞直到有空间可用,如果队列空了,出队操作将阻塞直到有元素可用;
队列可以为有界和无界队列,无界队列不会满,因此入队操作将不会阻塞;
下面将使用阻塞队列LinkedBlockingQueue举个生产者-消费者例子,生产者每隔1秒生产1个产品,然后有6个消费者在消费产品,可以发现,每隔1秒,只有一个消费者能够获取到产品消费,其它线程只能等待...
CAS操作时Java的JUC包的实现基础。Java中的CAS操作依赖于Unsafe类的实现,它提供了硬件级别的原子操作。
来看看Unsafe内常用的比较设置的方法compareAndSwap:
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
它有四个参数,分别表示:对象,对象地址,预期值,修改值
CPU提供了两种方法来实现多处理器的原子操作:总线加锁或者缓存加锁。
总线加锁:总线加锁就是使用处理器提供的一个LOCK#信号,当一个处理器在总线上输出此信号时,其他处理器的请求都将被阻塞。此方法的缺点显而易见,加锁时,其他处理器均不能处理共享内存,消耗太大
缓存加锁:不直接操作主内存,而是操作高速缓存,通过缓存一致性协议来保证数据的一致性