java.util.concurrent并发包中提供了一系列的的同步工具类,这些基础类不管是否能在项目中使用到,了解一下使用方法和原理对java程序员来说都是有必要的。博主在看《java并发编程实战》这本书中提到了其中几个工具类,本文就对这些类进行简单的描述。

  CyclicBarrier(栅栏)

  4个朋友约好下班一起玩吃鸡,分别是M4,AWM,SKS,WIN94。这四个哥们下班时间不一样,决定好一个时间一起上号搞。

  大家约好到家就开游戏,必须珍惜生命,争分夺秒玩游戏。

  我们用栅栏来模仿一下场景:  

 public class CyclicBarrierTest {

     private static CyclicBarrier barrier = new CyclicBarrier(4);

     private static class EatChickenPlayer extends Thread {

         private String name;

         //下班时间
private Long offWorkTime; public EatChickenPlayer(String name, Long time) {
this.name = name;
this.offWorkTime = time;
} @Override
public void run() {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println(name + ":我上号了");
try {
barrier.await();
System.out.println(name + ":开打开打");
} catch (Exception e) {
e.printStackTrace();
}
}
}, offWorkTime);
}
} public static void main(String[] args) {
EatChickenPlayer m416 = new EatChickenPlayer("m416", 3000L);
EatChickenPlayer AWM = new EatChickenPlayer("AWM", 6000L);
EatChickenPlayer SKS = new EatChickenPlayer("SKS", 9000L);
EatChickenPlayer win94 = new EatChickenPlayer("win94", 4000L);
m416.start();
AWM.start();
SKS.start();
win94.start();
}
}

  运行一下代码,感受一下,

  

  栅栏通常阻塞一系列线程,当所有需要的线程都达到栅栏位置,才能继续执行。所以,栅栏可以理解为等待其他的线程到达对应的位置,在一起执行。

  在做一些并发测试的时候,有时候需要所有线程都执行到相应的位置,让它们同时执行。而且栅栏是可以重复利用的,当栅栏开放后,栅栏会进行重置,然后对后续的线程进行拦截。如果await调用超时,或者await的线程被中断,栅栏就被认为是打破了,所有await的线程都会中止并且抛出BrokenBarrierException。如果成功通过栅栏,那么await将为每个线程返回一个唯一的到达索引号,我们可以通过索引来选举一个领导线程。并在下一次循环中,通过领导线程执行一些特殊工作。

  CountDownLatch(闭锁)

  好不容易,四个人都到到齐了,纷纷上号。要进行游戏,必须等队伍里所有人都点击准备完成,游戏才能开始。这种时候可以时候,我们可以使用闭锁来实现这种业务场景。

 public class CountDownLatchTest {

     private static CountDownLatch countDownLatch = new CountDownLatch(4);

     public static class EatChicken extends Thread {

         private String name;

         private int time;

         public EatChicken(String name, int time) {
this.name = name;
this.time = time;
} @Override
public void run() {
System.out.println(name + "准备" + time + "秒");
try {
SECONDS.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name + "衣服换好了");
countDownLatch.countDown();
}
} public static void main(String[] args) throws InterruptedException {
System.out.println("-----等待所有人准备-----");
EatChicken m416 = new EatChicken("m416", 1);
EatChicken AWM = new EatChicken("AWM", 2);
EatChicken SKS = new EatChicken("SKS", 2);
EatChicken win94 = new EatChicken("win94", 3);
m416.start();
AWM.start();
SKS.start();
win94.start(); countDownLatch.await();
System.out.println("-----所有人准备好了-----");
System.out.println("-----游戏开始-----");
}

  运行程序:

  

  闭锁初看跟栅栏非常相似,它们作为工具类,都能作为屏障,等待线程执行到一定的地方。闭锁跟栅栏的区别,就是闭锁是一次性的,当闭锁完全打开后就不能关闭了。栅栏打开之后,放行等待之后,栅栏就被重置,等待下一次开启。闭锁使用countDown()的时候,线程不会阻塞,继续运行。栅栏没有类似的countDown()方法,使用await()的时候,还需要等待的线程数-1,直到需要等待的线程数为0的时候,栅栏打开。

  Semaphore(信号量)

  有的时候,不仅这四位老哥去玩,时不时的M24也要来一起玩。这个时间,就只能大家一起抢位置了。没能挤进队伍的老哥内心百感交集,欲说还休。

  

  我们可以用信号量来模拟。

 public class SemaphoreTest {

     private static Semaphore semaphore = new Semaphore(4);

     private static class EatChickenPlayer extends Thread {

         private String name;

         public EatChickenPlayer(String name) {
this.name = name;
} @Override
public void run() {
if (semaphore.tryAcquire()) {
System.out.println(name + ":我进入游戏啦");
} else {
System.out.println(name + ":卧槽,队伍满了");
}
}
} public static void main(String[] args) throws InterruptedException {
EatChickenPlayer m416 = new EatChickenPlayer("m416");
EatChickenPlayer AWM = new EatChickenPlayer("AWM");
EatChickenPlayer SKS = new EatChickenPlayer("SKS");
EatChickenPlayer win94 = new EatChickenPlayer("win94");
EatChickenPlayer M24 = new EatChickenPlayer("M24");
m416.start();
AWM.start();
SKS.start();
win94.start();
M24.start();
}

  运行一下代码:  

  

  信号量用来控制同时访问某特定资源的操作数量。通过acquire()阻塞获取资格。或者使用tryAcquire()方法获取,及时返回结果,获取权限成功则返回ture,获取失败返回false。当权限已经使用完毕后,调用release()或者release(int permits) 方法释放权限。

  FutureTask

  游戏终于开始了,落地的时候,发现有四个房子,四位胸怀吃鸡的老哥分配好各走一个房子收集里面的东西。收集出来之后一起分东西。这里把每个老哥去房子里舔装备作为一个Task。我们用FutureTask来模拟一下这个场景:

  

 package com.chinaredstar.jc.lock;

 import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.*;
import java.util.stream.Collectors; public class FutureTaskTest { /**
* 固定的4线程,线程池
*/
private static ExecutorService threadPoolExecutor = Executors.newFixedThreadPool(4); static class Equipment {
/**
* 这里简单模拟一下,
* 1、子弹 2、枪械 3、药包
*/
private Integer type; /**
* 数量
*/
private Integer num; public Equipment(Integer type, Integer num) {
this.type = type;
this.num = num;
} public Integer getType() {
return type;
} public void setType(Integer type) {
this.type = type;
} public Integer getNum() {
return num;
} public void setNum(Integer num) {
this.num = num;
} } /**
* 舔装备人物类
*/
static class CollectTask implements Callable {
private String name; public CollectTask(String name) {
this.name = name;
} @Override
public List<Equipment> call() throws Exception {
return generatorEquipment(name);
}
} public static List<Equipment> generatorEquipment(String name) { List<Equipment> list = new ArrayList<>(); Random r = new Random();
//子弹
Equipment bullet = new Equipment(1, r.nextInt(100));
list.add(bullet);
System.out.println(name + ":捡到子弹" + bullet.num + "发");
//枪
Equipment gun = new Equipment(2, r.nextInt(3));
System.out.println(name + ":捡到枪" + gun.num + " 把");
list.add(gun);
//药包
Equipment bandage = new Equipment(3, r.nextInt(10));
System.out.println(name + ":捡到绷带" + bandage.num + " 个");
list.add(bandage);
return list;
} public static void main(String[] args) throws ExecutionException, InterruptedException {
//生成任务
CollectTask AWM = new CollectTask("AWM");
CollectTask m416 = new CollectTask("m416");
CollectTask SKS = new CollectTask("SKS");
CollectTask win94 = new CollectTask("win94");
//生成任务交给线程池
Future AWM_future = threadPoolExecutor.submit(AWM);
Future m416_future = threadPoolExecutor.submit(m416);
Future SKS_future = threadPoolExecutor.submit(SKS);
Future win94_future = threadPoolExecutor.submit(win94); //结果放在一起
List<Future> futureList = new ArrayList<>();
futureList.add(AWM_future);
futureList.add(m416_future);
futureList.add(SKS_future);
futureList.add(win94_future); //结果统一在一起
List<Equipment> taskResultList = new ArrayList<>();
for (Future<List<Equipment>> future : futureList) {
taskResultList.addAll(future.get());
} //打印出来看看都有些啥
Map<Integer, Integer> tolal = taskResultList.stream().collect(Collectors.groupingBy(
Equipment::getType, Collectors.summingInt(Equipment::getNum)));
tolal.entrySet();
for (Map.Entry<Integer, Integer> entry : tolal.entrySet()) {
if (entry.getKey() == 1) {
System.out.println("总共有子弹:" + entry.getValue());
}
if (entry.getKey() == 2) {
System.out.println("总共有枪:" + entry.getValue());
}
if (entry.getKey() == 3) {
System.out.println("总共有药包:" + entry.getValue());
}
} } }

  运行后的代码结果: 

  

  

  

java.util.concurrent中的几种同步工具类的更多相关文章

  1. [Google Guava] 2.3-强大的集合工具类:java.util.Collections中未包含的集合工具

    原文链接 译文链接 译者:沈义扬,校对:丁一 尚未完成: Queues, Tables工具类 任何对JDK集合框架有经验的程序员都熟悉和喜欢java.util.Collections包含的工具方法.G ...

  2. java.util.concurrent中的常用组件

    一. CountDownLatch 一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待. CountDownLatch的一个非常典型的应用场景是:有一个任务想要往下执 ...

  3. 集合-强大的集合工具类:java.util.Collections中未包含的集合工具

    任何对JDK集合框架有经验的程序员都熟悉和喜欢java.util.Collections包含的工具方法.Guava沿着这些路线提供了更多的工具方法:适用于所有集合的静态方法.这是Guava最流行和成熟 ...

  4. [Google Guava] 强大的集合工具类:java.util.Collections中未包含的集合工具

    转载的,有问题请联系我 原文链接 译文链接 译者:沈义扬,校对:丁一 尚未完成: Queues, Tables工具类 任何对JDK集合框架有经验的程序员都熟悉和喜欢java.util.Collecti ...

  5. 005-guava 集合-集合工具类-java.util.Collections中未包含的集合工具[Maps,Lists,Sets],Iterables、Multisets、Multimaps、Tables

    一.概述 工具类与特定集合接口的对应关系归纳如下: 集合接口 属于JDK还是Guava 对应的Guava工具类 Collection JDK Collections2:不要和java.util.Col ...

  6. java.util.concurrent介绍【转】

    java.util.concurrent介绍   java.util.concurrent 包含许多线程安全.测试良好.高性能的并发构建块.不客气地说,创建 java.util.concurrent ...

  7. java.util.concurrent

    软件包 java.util.concurrent 的描述 在并发编程中很常用的实用工具类.此包包括了几个小的.已标准化的可扩展框架,以及一些提供有用功能的类,没有这些类,这些功能会很难实现或实现起来冗 ...

  8. Java 理论与实践: 流行的原子——新原子类是 java.util.concurrent 的隐藏精华(转载)

    简介: 在 JDK 5.0 之前,如果不使用本机代码,就不能用 Java 语言编写无等待.无锁定的算法.在 java.util.concurrent 中添加原子变量类之后,这种情况发生了变化.请跟随并 ...

  9. java.util.concurrent.CountDownLatch

    闭锁是一种同步工具类,可以延迟线程的进度直到闭锁到达终止状态. 闭锁的作用相当于一扇门,在闭锁到达结束状态之前,这扇门一直是关闭的,任何线程都不能通过这扇门,当闭锁到达结束状态时,这扇门会打开并允许所 ...

随机推荐

  1. LeetCode刷题笔记-回溯法-分割回文串

    题目描述: 给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串. 返回 s 所有可能的分割方案. 示例: 输入: "aab"输出:[ ["aa", ...

  2. VS新建工程或者新建项时 出现未定义标识符号

    VS新建工程或者新建项时 出现未定义标识符号,编译之后不影响运行,但是看着很不舒服,影响效率. 解决办法:属性--->VC++目录-->包含目录-->编辑,将自己所用QT的inclu ...

  3. HtmlCleanner结合xpath用法(转载)

    HtmlCleaner cleaner = new HtmlCleaner(); TagNode node = cleaner.clean(new URL("http://finance.s ...

  4. 为什么 TCP 建立连接是三次握手,关闭连接确是四次挥手呢?

    Java技术栈 www.javastack.cn 优秀的Java技术公众号 作者:小书go https://blog.csdn.net/qzcsu/article/details/72861891 背 ...

  5. pandas中axis的含义

    定义一个dataframe: >>> df a b0 1 31 2 4 现在看两种用法: 1.求行的均值 >>> df.mean(axis=1)0 2.01 3.0 ...

  6. PHP算法之两数之和

    给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但是,你不能重复利用这个数组中同样的元 ...

  7. 使用ajax怎么请求跨域资源

    1.ajax中添加“xhrFields”和“crossDomain”,如: $.ajax({ url: url, data: data, type: "post", xhrFiel ...

  8. Java 对系统信号的通知获取

    主要介绍Java 如何对系统信号通知进行获取和处理.直接上demo @SuppressWarnings("restriction")public class Test1 imple ...

  9. django中写form表单时csrf_token的作用

    之前在学习django的时候,在template中写form时,出现错误.百度,google后要加{% csrf_token %}才可以,之前一直也没研究,只是知道要加个这个东西,具体是什么也不明白. ...

  10. R语言中的线性判别分析_r语言 线性判别分析

    R语言中的线性判别分析_r语言 线性判别分析 在R语言中,线性判别分析(Liner Discriminant Analysis,简称LDA),依靠软件包MASS中有线性判别函数lqa()来实现.该函数 ...