zoukankan      html  css  js  c++  java
  • Java多线程同步器

    Java中多线程开发时,离不开线程的分工协作,常用的多线程的同步器有如下几种:

    1、CountDownLatch

    应用场景:等待一组线程任务完成后在继续执行当前线程

    用法:定义一个CountDownLatch变量latch,在当前线程中调用latch.await()方法,在要等待的一组线程中执行完后调用latch.countDown()方法,这样当该做线程都调用过latch.countDown()方法后就开始执行当前线程latch.await()后的方法。

    CountDownLatch的用法:

    CountDownLatch典型用法:1、某一线程在开始运行前等待n个线程执行完毕。将CountDownLatch的计数器初始化为new CountDownLatch(n),每当一个任务线程执行完毕,就将计数器减1 countdownLatch.countDown(),当计数器的值变为0时,在CountDownLatch上await()的线程就会被唤醒。一个典型应用场景就是启动一个服务时,主线程需要等待多个组件加载完毕,之后再继续执行。

    CountDownLatch典型用法:2、实现多个线程开始执行任务的最大并行性。注意是并行性,不是并发,强调的是多个线程在某一时刻同时开始执行。类似于赛跑,将多个线程放到起点,等待发令枪响,然后同时开跑。做法是初始化一个共享的CountDownLatch(1),将其计算器初始化为1,多个线程在开始执行任务前首先countdownlatch.await(),当主线程调用countDown()时,计数器变为0,多个线程同时被唤醒

    CountDownLatch的不足: CountDownLatch是一次性的,计算器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当CountDownLatch使用完毕后,它不能再次被使用。

    CountDownLatch(倒计时计算器)使用说明:

    public void countDown()

      递减锁存器的计数,如果计数到达零,则释放所有等待的线程。如果当前计数大于零,则将计数减少.

    public boolean await(long timeout,TimeUnit unit) throws InterruptedException

      使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断或超出了指定的等待时间。如果当前计数为零,则此方法立刻返回true值。

      如果当前计数大于零,则出于线程调度目的,将禁用当前线程,且在发生以下三种情况之一前,该线程将一直出于休眠状态:

      由于调用countDown()方法,计数到达零;或者其他某个线程中断当前线程;或者已超出指定的等待时间。

    • 如果计数到达零,则该方法返回true值。
    • 如果当前线程,在进入此方法时已经设置了该线程的中断状态;或者在等待时被中断,则抛出InterruptedException,并且清除当前线程的已中断状态。
    • 如果超出了指定的等待时间,则返回值为false。如果该时间小于等于零,则该方法根本不会等待。

    参数: timeout-要等待的最长时间

        unit-timeout 参数的时间单位

    返回:如果计数到达零,则返回true;如果在计数到达零之前超过了等待时间,则返回false

    抛出:InterruptedException-如果当前线程在等待时被中断

    2、CyclicBarrier

    应用场景:等待一组线程到达某个点后一起执行,该组线程达到指定点后可以再次循环执行。也可用于一组线程达达某个点后再执行某个方法。

    用法:定义一个CyclicBarrier变量barrier,线程达到某个约定点时调用barrier.await()方法,当该组所有线程都调用了barrier.await()方法后改组线程一起向下执行

    CyclicBarrier和CountDownLatch的区别

    • CountDownLatch的计数器只能使用一次。而CyclicBarrier的计数器可以使用reset() 方法重置。所以CyclicBarrier能处理更为复杂的业务场景,比如如果计算发生错误,可以重置计数器,并让线程们重新执行一次。
    • CyclicBarrier还提供其他有用的方法,比如getNumberWaiting方法可以获得CyclicBarrier阻塞的线程数量。isBroken方法用来知道阻塞的线程是否被中断。

    CyclicBarrier方法说明 :
    CyclicBarrier(parties)

    初始化相互等待的线程数量的构造方法。

    CyclicBarrier(parties,Runnable barrierAction)

    初始化相互等待的线程数量以及屏障线程的构造方法。

    屏障线程的运行时机:等待的线程数量=parties之后,CyclicBarrier打开屏障之前。

    举例:在分组计算中,每个线程负责一部分计算,最终这些线程计算结束之后,交由屏障线程进行汇总计算。

    getParties()

    获取CyclicBarrier打开屏障的线程数量,也成为方数。

    getNumberWaiting()

    获取正在CyclicBarrier上等待的线程数量。

    await()

    在CyclicBarrier上进行阻塞等待,直到发生以下情形之一:

    在CyclicBarrier上等待的线程数量达到parties,则所有线程被释放,继续执行。
    当前线程被中断,则抛出InterruptedException异常,并停止等待,继续执行。
    其他等待的线程被中断,则当前线程抛出BrokenBarrierException异常,并停止等待,继续执行。
    其他等待的线程超时,则当前线程抛出BrokenBarrierException异常,并停止等待,继续执行。
    其他线程调用CyclicBarrier.reset()方法,则当前线程抛出BrokenBarrierException异常,并停止等待,继续执行。
    await(timeout,TimeUnit)

    在CyclicBarrier上进行限时的阻塞等待,直到发生以下情形之一:

    在CyclicBarrier上等待的线程数量达到parties,则所有线程被释放,继续执行。
    当前线程被中断,则抛出InterruptedException异常,并停止等待,继续执行。
    当前线程等待超时,则抛出TimeoutException异常,并停止等待,继续执行。
    其他等待的线程被中断,则当前线程抛出BrokenBarrierException异常,并停止等待,继续执行。
    其他等待的线程超时,则当前线程抛出BrokenBarrierException异常,并停止等待,继续执行。
    其他线程调用CyclicBarrier.reset()方法,则当前线程抛出BrokenBarrierException异常,并停止等待,继续执行。
    isBroken()

    获取是否破损标志位broken的值,此值有以下几种情况:

    CyclicBarrier初始化时,broken=false,表示屏障未破损。
    如果正在等待的线程被中断,则broken=true,表示屏障破损。
    如果正在等待的线程超时,则broken=true,表示屏障破损。
    如果有线程调用CyclicBarrier.reset()方法,则broken=false,表示屏障回到未破损状态。
    reset()

    使得CyclicBarrier回归初始状态,直观来看它做了两件事:

    如果有正在等待的线程,则会抛出BrokenBarrierException异常,且这些线程停止等待,继续执行。
    将是否破损标志位broken置为false。

    3、Semaphore

    应用场景:对于一组有限制都资源访问。比如餐厅有5个位置但同时有7个人要吃饭,则要控制7个人对餐位的并发实用。

    用法:定义Semaphore变量semaphore包含受限的资源个数,每个人要来用餐时先调用semaphore.acquire()方法获取一个餐位(若没有餐位,则阻塞等待),用完餐后调用semaphore.release()释放餐位给其它人用。Semaphore 是 synchronized 的加强版,作用是控制线程的并发数量(synchronized 只能控制单一线程),就这一点而言,单纯的synchronized 关键字是实现不了的。

    Semaphore主要方法:

    Semaphore(int permits):构造方法,创建具有给定许可数的计数信号量并设置为非公平信号量。

    Semaphore(int permits,boolean fair):构造方法,当fair等于true时,创建具有给定许可数的计数信号量并设置为公平信号量。

    void acquire():从此信号量获取一个许可前线程将一直阻塞。相当于一辆车占了一个车位。

    void acquire(int n):从此信号量获取给定数目许可,在提供这些许可前一直将线程阻塞。比如n=2,就相当于一辆车占了两个车位。

    void release():释放一个许可,将其返回给信号量。就如同车开走返回一个车位。

    void release(int n):释放n个许可。

    int availablePermits():当前可用的许可数。

    4、阻塞队列

    应用场景:可用于实现简单的生产者消费者模型。

    用法:生产者线程put元素到队列,若队列满则组赛到队列有空间;消费者不断从队列take获取元素,若队列空则组赛道队列有元素。

  • 相关阅读:
    又一道简单的题
    atoi函数的使用(将字符串转换成整型数)
    【贪心】Radar Installation(POJ1328)
    【BFS】鸣人与佐助
    谍报分析
    适配器模式(C++实现)
    策略模式(C++)
    工厂模式(C++实现)
    桥接模式(C++实现)
    关于getMemory函数的几点思考
  • 原文地址:https://www.cnblogs.com/alex-xyl/p/12468869.html
Copyright © 2011-2022 走看看