其他分享
首页 > 其他分享> > 同步类

同步类

作者:互联网

1.Semaphore (信号量)

Semaphore 是一种基于计数的信号量,用来控制同时访问的线程数。

它可以设定一个阈值,基于此,多个线程竞争获取许可信号,做完自己的申请后归还,超过阈值后,线程申请许可信号将会被阻塞。Semaphore 可以用来构建一些对象池,资源池之类的,比如数据库连接池

实现互斥锁(计数器为 1) 我们也可以创建计数为 1 的 Semaphore,将其作为一种类似互斥锁的机制,这也叫二元信号量, 表示两种互斥状态。

 1 // 创建一个计数阈值为 5 的信号量对象
 2 // 只能 5 个线程同时访问
 3 Semaphore semp = new Semaphore(5);
 4 try { // 申请许可
 5 semp.acquire();
 6 try {
 7 // 业务逻辑
 8 } catch (Exception e) {
 9 } finally {
10 // 释放许可
11 semp.release();
12 }
13 } catch (InterruptedException e) {
14 }

Semaphore 中也有Sync内部类(继承AQS抽象类),semp.acquire()方法和semp.release()方法底层使用Sync类CAS修改其内部volatile共享变量state来获取许可。state可以设置大于1,也就是成为了共享锁。

Semaphore semp = new Semaphore(5);就是将state设置为5,每次一个线程获得信号量就-1,释放一个信号量就+1。

 

Semaphore 与 ReentrantLock比较

Semaphore 基本能完成 ReentrantLock 的所有工作,使用方法也与之类似,通过 acquire()与 release()方法来获得和释放临界资源。经实测,Semaphone.acquire()方法默认为可响应中断锁, 与 ReentrantLock.lockInterruptibly()作用效果一致,也就是说在等待临界资源的过程中可以被 Thread.interrupt()方法中断。 此外,Semaphore 也实现了可轮询的锁请求与定时锁的功能,除了方法名 tryAcquire 与 tryLock 不同,其使用方法与 ReentrantLock 几乎一致。Semaphore 也提供了公平与非公平锁的机制,也可在构造函数中进行设定。 Semaphore 的锁释放操作也由手动进行,因此与 ReentrantLock 一样,为避免线程因抛出异常而无法正常释放锁的情况发生,释放锁的操作也必须在 finally 代码块中完成。

 

 

CountDownLatch

CountDownLatch(线程计数器 )
 

作用:让一个线程等待其他几个线程执行特定操作(调用countDown方法)后才能继续执行

CountDownLatch 类位于 java.util.concurrent 包下,利用它可以实现类似计数器的功能。比如有 一个任务 A,它要等待其他 4 个任务执行完毕之后才能执行,此时就可以利用 CountDownLatch 来实现这种功能了。

CountDownLatch 调用await方法当前线程会被阻塞,等待latch调用countDown(),count为0(Sync中state为0),此线程就会被唤醒。

 

 1 final CountDownLatch latch = new CountDownLatch(2);
 2 new Thread(){public void run() {
 3 System.out.println("子线程"+Thread.currentThread().getName()+"正在执行");
 4  Thread.sleep(3000);
 5  System.out.println("子线程"+Thread.currentThread().getName()+"执行完毕");
 6  //重点
 7  latch.countDown();
 8 };}.start();
 9 new Thread(){ public void run() {
10 System.out.println("子线程"+Thread.currentThread().getName()+"正在执行");
11  Thread.sleep(3000);
12  System.out.println("子线程"+Thread.currentThread().getName()+"执行完毕");
13  latch.countDown();
14 };}.start();
15 System.out.println("等待 2 个子线程执行完毕...");
16 //重点
17 latch.await();  //主线程执行,等待两个子线程调用 latch.countDown();
18 System.out.println("2 个子线程已经执行完毕");
19 System.out.println("继续执行主线程");
20 }

 

CyclicBarrier

回环栅栏-等待至 barrier 状态再全部同时执行

字面意思回环栅栏,通过它可以实现让一组线程等待至某个状态(一组线程都调用await)之后再全部同时后续执行

叫做回环是因为当所有等待线程都被释放以后,CyclicBarrier 可以被重用。我们暂且把这个状态就叫做 barrier,当调用 await()方法之后,线程就处于 barrier 了。

CyclicBarrier 中最重要的方法就是 await 方法,它有 2 个重载版本: 1. public int await():用来挂起当前线程,直至所有线程都到达 barrier 状态再同时执行后续任务; 2. public int await(long timeout, TimeUnit unit):让这些线程等待至一定的时间,如果还有线程没有到达 barrier 状态就直接让到达 barrier 的线程执行后续任务。

具体使用如下,另外 CyclicBarrier 是可以重用的。

 

 1 public static void main(String[] args) {
 2  int N = 4;
 3     
 4  CyclicBarrier barrier = new CyclicBarrier(N);
 5     
 6  for(int i=0;i<N;i++)
 7      
 8  new Writer(barrier).start();
 9     
10  }
11  static class Writer extends Thread{
12    private CyclicBarrier cyclicBarrier;
13    public Writer(CyclicBarrier cyclicBarrier) {
14    this.cyclicBarrier = cyclicBarrier;
15    }
16   @Override
17   public void run() {
18     try {
19     Thread.sleep(5000); //以睡眠来模拟线程需要预定写入数据操作
20     System.out.println("线程"+Thread.currentThread().getName()+"写入数据完
21     毕,等待其他线程写入完毕");
22                    
23     cyclicBarrier.await();
24                    
25  } catch (InterruptedException e) {
26  e.printStackTrace();
27  }catch(BrokenBarrierException e){
28  e.printStackTrace();
29  }
30  System.out.println("所有线程写入完毕,继续处理其他任务,比如数据操作");
31  }
32  }

 

 

 

 

 

 

 

 

 

 

标签:同步,barrier,Thread,Semaphore,System,线程,CountDownLatch
来源: https://www.cnblogs.com/SEU-ZCY/p/16461188.html