Java同步工具类

同步工具类可与是任何一个对象,只要它根据自身的状态来协调线程的控制流。阻塞队列可与作为同步工具类,其他类型的同步工具类还包括 信号量(Semaphore)、栅栏(Barrier)以及闭锁(Latch)。
所有的同步工具类都包含一些特定的结构化属性:它们封装了一些状态,这些状态将决定执行同步工具类的线程是继续执行还是等待,此外还提供了一些方法对状态进行操作,以及另一些方法用于高效地等待同步工具类进入到预期状态。
   
    闭锁:闭锁是一种同步工具类,可以延迟线程的进度直到其(闭锁)到达种终止状态。闭锁的作用相当于一扇门:在闭锁到达结束状态之前,这扇门一直关闭,没有任何线程可以通过,当到达结束状态时,这扇门会打开并允许所有的线程通过。当闭锁到达结束状态后,将不会改变状态,即这扇门会永远保持打开状态。 闭锁可以用来确保某些活动直到其他活动都完成后才继续执行。例如:
    · 确保某个计算在其需要的所有资源都被初始化之后才继续执行。二元闭锁(包括两个状态)可以用来表示“资源R已经被初始化”,而所有需要R的操作都必须现在这个闭锁上等待。
    · 确保某个服务在其依赖的所有其他服务都已经启动之后才启动。每个服务都有一个相关的二元闭锁。当启动服务S时,将首先在S依赖的其他服务的闭锁上等待,在所以依赖的服务都启动后会释放闭锁S,这样其他依赖S的服务才能继续执行。
    · 等待直到某个操作的所有参与者都就绪再继续执行。在这种情况中,当所有参与者都准备就绪时,闭锁将到达结束状态。
CountDownLatch是一种灵活的闭锁实现,可以在上述的各种情况中使用,它可以使一个或多个线程等待一组事件发生。闭锁状态包括一个计数器,该计数器被初始化为一个正数,表示需要等待的事件数量。countDown方法递减计数器,表示有一个事件已经发生了,而await方法等待计数器达到零,或者等待中的线程中断,或者等待超时。
闭锁的两种常见用法:
public class TestHarness {
        public long timeTasks( int nThreads , final Runnable task ) throws InterruptedException{
              final CountDownLatch startGate = new CountDownLatch(1); //开始门
              final CountDownLatch endGate = new CountDownLatch( nThreads ); //结束门
              for ( int i =0; i < nThreads ; i ++) {
                    Thread t = new Thread() {
                            public void run() {
                                  try {
                                         startGate .await();  //等到开始门开启
                                         try {
                                                task .run(); //线程执行任务
                                        } finally {
                                                endGate .countDown();  //结束门等待的线程减一
                                        }
                                 } catch (InterruptedException ignored ) {}
                           }
                    };
                     t .start();
             }
              long start = System. nanoTime ();
              startGate .countDown();  //开始门减一,闭锁结束,所有线程开始执行,每个线程执行完任务后结束门闭锁等待的线程会减一
              endGate .await(); //等待结束门开启
              long end = System. nanoTime ();
              return end - start ;
             
       }
       
}

FutureTask
    FutureTask表示的计算是通过Callable来实现的,相当于一种可生成结果的Runnable,并且可以处于以下3种状态:等待运行、正在运行和运行完成。“执行完成”表示计算的所有可能结束方式,包括正常结束、由于取消而结束和由于异常而结束等。当FutureTask进入完成状态后,它会永远停止在这个状态上。
    Future.get的行为取决于任务的状态。如果任务已经完成,那么get会立即返回结果,否则get将阻塞直到任务进入完成状态,然后返回结果或抛出异常。
    FutureTask在Executor 框架中表示异步任务,此外还可以用来表示一些时间较长的计算,这些计算可以在使用计算结果之前启动。通过提前启动计算,可以减少在等待结果时需要的时间。
信号量(Semaphore)
    计数信号量用来控制同时访问某个特定资源的操作数量,或者同时执行某个指定操作的数量。计数信号量还可以用来实现某种资源池,或者对容器施加边界。

栅栏(Barrier)
    栅栏(Barrier)类似于闭锁,它能阻塞一组线程直到某个事件发生。栅栏与闭锁的关键区别在于,所有线程必须同时到达栅栏位置才能继续执行。 闭锁用于等待事件,而栅栏用于等待其他线程。
    CyclicBarrier 可以使一定数量的参与方反复地在栅栏位置汇集,它在并行迭代算法中非常有用:这种算法通常将一个问题拆分成一系列相互独立的子问题。当线程到达栅栏位置时将调用 await 方法,这个方法将阻塞直到所有线程都到达栅栏位置。如果所有线程都到达了栅栏位置,那么栅栏将打开,此时所有线程被释放,而栅栏将被重置以便下次使用。如果对 await 的调用超时,或者 await 阻塞的线程被中断,那么栅栏就被认为是打破了,所有阻塞的 await 调用都将终止并抛出 BrokenBarrierException 。如果成功通过栅栏,那么 await 将为每个线程都返回一个唯一的到达索引号。CyclicBarrier还可以使你将一个栅栏操作传递给构造函数,这是一个Runnable,当成功通过栅栏时会(在一个子任务线程中)执行它,但在阻塞线程被释放之前是不能执行的。

两方栅栏(Two-Party)
    另一种形式的栅栏是Exchanger,它是一种两方(Two-Party)栅栏。当两方执行不对称的操作时,Exchanger会非常有用。最简单的方案是:当缓冲区被填满时,由填充任务进行交换,当缓冲区会空时,由清空任务进行交换。
    如果新数据的到达率不可预测,那么一些数据的处理过程就将延迟。另一个方法是,不仅当缓冲被填满时进行交换,并且当缓冲被填充到一定程度并保持一定时间后,也进行交换。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值