线程同步工具类 2020面试必看

CountDownLatch和CyclicBarrier都有让多个线程等待同步然后再开始下一步动作的意思,但是CountDownLatch的下一步的动作实施者是主线程,主线程等待其他线程,具有不可重复性;而CyclicBarrier的下一步动作实施者还是“其他线程”本身,线程互相等待,具有往复多次实施动作的特点。

Condition

Condition是一种广义上的条件队列,它为线程提供了一种更为灵活的等待/通知模式,Condition是一个接口,它的实现ConditionObjectAQS的一个内部类,Conditon必须配合锁一起使用。condition调用await会释放锁,调用condition.await()、condition.signal()的线程必须已经获取了锁,否则会抛出IllegalMonitorStateException异常.

CountDownLatch

其作用是设置一个屏障,当到达屏障点的线程达到指定数量时,继续往下执行。用于控制多线程在某一个点同步等待。内部采用共享锁实现。

构造方法:CountDownLatch(int countcount表示需要达到屏障点的线程数量

核心方法:

    countDown()线程调用该方法,计数减1,当计数为0,放行

    await() 屏障点,使当前线程阻塞,直到count为零时才往下继续执行

缺点:不能重用

循环栅栏CyclicBarrier

CyclicBarrier是一个同步辅助类,它允许一组线程互相等待。

它有两个构造方法:

    CyclicBarrier(int parties):创建一个新的CyclicBarrier,拦截线程数为parties

    CyclicBarrier(int parties,Runnable barrierAction):创建一个CyclicBarrier,拦截线程数位parties,当所有线程到达屏障点时,执行barrierAction中的动作

核心方法await()

优点:可重用

缺点:不能动态增加计数,也不能动态减少计数

信号量Semaphore

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

作用是使得两个线程之间可以进行数据交换

构造方法:

    Exchanger() 创建一个交换器

核心方法:

exchange(E e)执行数据交换,此方法会阻塞,直到有另一个线程和它进行数据交换或者被打断为止

LinkedBlockingQueue

阻塞队列提供了可阻塞的入队和出对操作,如果队列满了,入队操作将阻塞直到有空间可用,如果队列空了,出队操作将阻塞直到有元素可用;

队列可以为有界和无界队列,无界队列不会满,因此入队操作将不会阻塞;

下面将使用阻塞队列LinkedBlockingQueue举个生产者-消费者例子,生产者每隔1秒生产1个产品,然后有6个消费者在消费产品,可以发现,每隔1秒,只有一个消费者能够获取到产品消费,其它线程只能等待...

 

Java的CAS操作

CAS操作时Java的JUC包的实现基础。Java中的CAS操作依赖于Unsafe类的实现,它提供了硬件级别的原子操作。

来看看Unsafe内常用的比较设置的方法compareAndSwap:

public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

它有四个参数,分别表示:对象,对象地址,预期值,修改值

CPU提供了两种方法来实现多处理器的原子操作:总线加锁或者缓存加锁。

总线加锁:总线加锁就是使用处理器提供的一个LOCK#信号,当一个处理器在总线上输出此信号时,其他处理器的请求都将被阻塞。此方法的缺点显而易见,加锁时,其他处理器均不能处理共享内存,消耗太大

缓存加锁:不直接操作主内存,而是操作高速缓存,通过缓存一致性协议来保证数据的一致性

 

你可能感兴趣的:(多线程并发,多线程,并发编程)