java不能初始化工具类_Java并发工具类

该篇文章介绍CountDownLatch,CycliBarrier,Semaphore,Exchanger并发工具类的使用

CountDownLatch

CountDownLatch允许一个或者多个线程等待其他线程完成操作。

在多线程中可能出现A线程需要等待B线程和C线程执行完毕才会执行,而A线程又不知道B和C线程具体什么时候能够结束,所以需要一种通知方式告诉A线程B和C线程已经执行完毕,在Java中可以通过先使A线程await(),等待B和C线程执行完毕在notifyAll()唤醒A线程。

Threadl类有一个join()方法可以实现这个功能,

join():在一个线程中调用另一个线程的join(),会使得被调用join()的线程执行完毕,调用线程才会继续执行下去。

查看Thread类的join()方法

63476877a94a直到join线程中止后,线程的this.notifyAll()方法会被调用,调用notifyAll()方法是在JVM里实现的

使用例子:main线程需等待thread1和thread2线程执行完毕才会继续执行

63476877a94a

结果:

63476877a94a

CountDownLatch的使用

CountDownLatch有着和join()相同的功能,但是比join()更加灵活,功能也更加强大。CountDownLatch可以在不同线程不同位置使用。

初始化

CountDownLatch countDownLatch = new CountDownLatch(int count);

count:表示一个计数值,每调用一次countDown()方法,该计数值会减一,当count=0时,其他线程执行完毕,唤醒主线程。

使用CountDownLatch 完成上面的例子

63476877a94a注意:使用CountDownLatch的时候确保计数值在最后为零,要不然主线程会一直等待下去,所以调用countDown()方法的时候,确保线程会执行到该方法。也可以设置超时时间await(long timeout, TimeUnit unit),

结果:

63476877a94a

CyclicBarrier

CyclicBarrier的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续运行。

在不同线程之间设置屏障

63476877a94a

先到达的线程进入等待,等待屏障打开

63476877a94a

当所有线程到达屏障后,屏障打开

初始化

第一种

CyclicBarrier c = new CyclicBarrier(int parties);

parties:表示拦截线程的数量

每个线程调用CyclicBarrier 的await(),表示当前线程到达屏障,当前线程会进入阻塞。当所有规定数量的线程到达屏障后,之前阻塞的线程线程都会唤醒。继续执行。(屏障打开后,所有线程的执行顺序是不确定的,根据线程竞争cpu,获取执行时间)

第二种

CyclicBarrier c = new CyclicBarrier(int parties, Runnable barrierAction)

barrierAction:屏障线程

设置屏障线程,既然所有线程都在同一个点阻塞(同步点),那么这个阻塞点就很有意义,所以就有了屏障线程的出现,在所有线程到达屏障,但是屏障开没有打开,这个时间就是屏障线程的工作时间。

例如有一个5000大小的数组,统计数组中数字的和。可以将这个数组分成5分,每个线程处理1000个数字之和,当5个线程执行完毕,再有一个屏障线程处理这五个线程的和,这样得到最终的结果。

对上面的例子进行编码

63476877a94a

结果:

63476877a94a

CyclicBarrier常用API

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。

测试reset()

63476877a94a

结果

63476877a94a

CountDownLatch和CyclicBarrier的区别

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

semaPhore

Semaphore(信号量)是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源。

比如××马路要限制流量,只允许同时有一百辆车在这条路上行使,其他的都必须在路口等待,所以前一百辆车会看到绿灯,可以开进这条马路,后面的车会看到红灯,不能驶入××马路,但是如果前一百辆中有5辆车已经离开了××马路,那么后面就允许有5辆车驶入马路,这个例子里说的车就是线程,驶入马路就表示线程在执行,离开马路就表示线程执行完成,看见红灯就表示线程被阻塞,不能执行。

例子模拟100个线程 ,semaPhore限制10个线程。

63476877a94a

结果:每隔2秒打印10个线程

63476877a94a

semaPhore常用API

.tryAcquire():尝试获取许可证,立即获取返回true,否则返回false。

·intavailablePermits():返回此信号量中当前可用的许可证数。

·intgetQueueLength():返回正在等待获取许可证的线程数。

·booleanhasQueuedThreads():是否有线程正在等待获取许可证。

·void reducePermits(int reduction):减少reduction个许可证,是个protected方法。

·Collection getQueuedThreads():返回所有等待获取许可证的线程集合,是个protected方法

Exchanger

Exchanger(交换者)是一个用于线程间协作的工具类。Exchanger用于进行线程间的数据交换。它提供一个同步点,在这个同步点,两个线程可以交换彼此的数据。这两个线程通过exchange方法交换数据,如果第一个线程先执行exchange()方法,它会一直等待第二个线程也执行exchange方法,当两个线程都到达同步点时,这两个线程就可以交换数据,将本线程生产出来的数据传递给对方。

例子:模拟A,B两个线程之间信息的交换

63476877a94a

结果:

63476877a94a

如果两个线程有一个没有执行exchange()方法,则会一直等待,如果担心有特殊情况发生,避免一直等待,可以使用exchange(V x,longtimeout,TimeUnit unit)设置最大等待时长。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值