java并发工具类

java

字面意思:倒计时锁闩,该类可以实现一个线程在等其他多个线程执行完之后,继续执行。

入参是一个计数器的值,当一个线程执行完毕时调用countDown()方法,计数器值会减1,当计数器值为0时,被await()阻塞的线程将被唤醒。

CountDownLatch latch = new CountDownLatch(10);

大家都玩过王者荣耀的5V5排位吧,当己方5个人准备就绪,对方5人也准备就绪时,才可以进入B/P环节,也就是王者荣耀这个线程需要等待10位玩家的线程都准备完毕,然后才出发进入游戏的操作。

package com.duchong.concurrent;

import java.util.concurrent.CountDownLatch;

import java.util.concurrent.TimeUnit;

/**

* 模拟5V5排位,10个玩家都准备就绪,才开始进入游戏

* CountDownLatch :阻塞主线程,等子线程完成

* @author DUCHONG

* @since 2020-09-03 17:43:13

*/

public class CountDownLatchDemo {

public static final int playerNum=10;

public static void main(String[] args) {

final CountDownLatch latch = new CountDownLatch(10);

GameThread subThread = new GameThread(latch);

try {

//模拟5V5排位

for (int i = 1; i <= playerNum; i++) {

new Thread(subThread,"player-"+i).start();

TimeUnit.SECONDS.sleep(1L);

}

//阻塞主线程

latch.await();

}

catch (InterruptedException e) {

}

System.out.println("王者荣耀:玩家全部准备就绪,开始进入游戏");

}

/**

* 游戏子线程

*/

static class GameThread implements Runnable {

private CountDownLatch latch;

public GameThread(CountDownLatch latch) {

this.latch = latch;

}

@Override

public void run() {

try {

System.out.println(Thread.currentThread().getName()+"---准备就绪");

}

finally {

latch.countDown();

}

}

}

}

结果

二、CyclicBarrier

字面意思: 循环屏障,多个线程到达一个屏障点时被阻塞,直到最后一个线程到达屏障点时,屏障才会解除,所有被屏障拦截的线程继续运行。

第一个入参代表屏障接触时阻塞线程的数量。第二个入参代表屏障解除时要进行的操作

CyclicBarrier c = new CyclicBarrier(10, ()->System.out.println("屏障解除"));

await()方法其实是调用Conditionawait()

public class CyclicBarrier {

/** The lock for guarding barrier entry */

private final ReentrantLock lock = new ReentrantLock();

/** Condition to wait on until tripped */

private final Condition trip = lock.newCondition();

//....省略

public int await() throws InterruptedException, BrokenBarrierException {

try {

return dowait(false, 0L);

} catch (TimeoutException toe) {

throw new Error(toe); // cannot happen

}

}

//wait方法

private int dowait(boolean timed, long nanos)

throws InterruptedException, BrokenBarrierException,

TimeoutException {

//重入锁

final ReentrantLock lock = this.lock;

//加锁

lock.lock();

try {

final Generation g = generation;

if (g.broken)

throw new BrokenBarrierException();

if (Thread.interrupted()) {

breakBarrier();

throw new InterruptedException();

}

int index = --count;

if (index == 0) { // tripped

boolean ranAction = false;

try {

final Runnable command = barrierCommand;

if (command != null)

command.run();

ranAction = true;

nextGeneration();

return 0;

} finally {

if (!ranAction)

breakBarrier();

}

}

// 循环

for (;;) {

try {

if (!timed)

// 调用condition的await()方法

trip.await();

else if (nanos > 0L)

nanos = trip.awaitNanos(nanos);

} catch (InterruptedException ie) {

if (g == generation && ! g.broken) {

breakBarrier();

throw ie;

} else {

// We're about to finish waiting even if we had not

// been interrupted, so this interrupt is deemed to

// "belong" to subsequent execution.

Thread.currentThread().interrupt();

}

}

if (g.broken)

throw new BrokenBarrierException();

if (g != generation)

return index;

if (timed && nanos <= 0L) {

breakBarrier();

throw new TimeoutException();

}

}

} finally {

//解锁

lock.unlock();

}

}

//....省略

}

该类同样可以实现与CountDownLatch相同的效果

package com.duchong.concurrent;

import java.util.concurrent.BrokenBarrierException;

import java.util.concurrent.CyclicBarrier;

import java.util.concurrent.TimeUnit;

/**

* 模拟5V5排位,10个玩家都准备就绪,才开始进入游戏

* CyclicBarrier :阻塞子线程,当等待中的子线程数到达一定数量时,跳闸。

* @author DUCHONG

* @since 2020-09-03 17:41:35

*/

public class CyclicBarrierDemo {

public static final int playerNum=10;

/**

* 屏障,初始10 当await()的线程数量达到10时,跳闸。

*/

static CyclicBarrier c = new CyclicBarrier(playerNum, ()->System.out.println("王者荣耀:玩家全部准备就绪,开始进入游戏"));

public static void main(String[] args) {

try {

//

for (int i = 1; i <= playerNum; i++) {

new Thread(new GameThread(),"player-"+i).start();

TimeUnit.SECONDS.sleep(1L);

}

}

catch (InterruptedException e) {

e.printStackTrace();

}

}

/**

* 游戏子线程

*/

static class GameThread implements Runnable {

@Override

public void run() {

try {

System.out.println(Thread.currentThread().getName()+"---准备就绪");

//阻塞子线程

c.await();

System.out.println(Thread.currentThread().getName()+"---进入游戏");

} catch (InterruptedException e) {

e.printStackTrace();

} catch (BrokenBarrierException e) {

e.printStackTrace();

}

}

}

}

结果

三、Semaphore

字面意思:信号量,多个线程访问一个共享资源时,如果想控制对该资源访问的线程的数量,可以用这个工具类。

入参对象是一个许可的数量,如果数量大于1,则可以作为共享锁来使用,如果数量等于1,则可以作为排他锁来使用

acquire()方法表示得到一个许可,可以对共享资源进行操作, 如果许可数量分配完了,其他线程将阻塞, 直到已得到许可的线程释放许可后,才有机会再获取许可。

release()方法表示释放一个许可。

Semaphore semaphore=new Semaphore(5);

接着王者荣耀排位5V5的例子来讲,当玩家进入B/P环节,5个人,但是地图只有上中下三路,也就是说最多2个人去打野位置

package com.duchong.concurrent;

import java.util.concurrent.Semaphore;

import java.util.concurrent.TimeUnit;

/**

* 模拟进入5V5排位游戏后的B/P环节,五个人,上中下三路,最多2个人去打野位置

* Semaphore,对资源的并发数控制

* @author DUCHONG

* @since 2020-09-03 15:46

**/

public class SemaphoreDemo {

//打野人数

public static final int wildNum=2;

//总共人数

public static final int totalNum=5;

static Semaphore semaphore=new Semaphore(wildNum);

public static void main(String[] args) {

try {

for (int i = 1; i <=totalNum; i++) {

new Thread(new GameThread(semaphore),"player-"+i).start();

TimeUnit.SECONDS.sleep(1L);

}

}

catch (InterruptedException e) {

e.printStackTrace();

}

}

/**

* 游戏子线程

*/

static class GameThread implements Runnable {

private Semaphore semaphore;

public GameThread(Semaphore semaphore){

this.semaphore=semaphore;

}

@Override

public void run() {

try {

//抢到打野位置,最多两个人,其他人想选打野位时阻塞,除非抢到的人选择其他路

semaphore.acquire();

System.out.println(Thread.currentThread().getName()+"---抢到打野位");

TimeUnit.SECONDS.sleep(3L);

System.out.println(Thread.currentThread().getName()+"---犹豫了一下,选择了其他路");

}

catch (Exception e){

}

finally {

//新增一个许可

semaphore.release();

}

}

}

}

结果

同一时刻只有两个player获取到打野位置(共享资源)符合预期。

以上是 java并发工具类 的全部内容, 来源链接: utcz.com/z/390720.html

回到顶部