并发编程--Concurrent-工具类介绍
并发编程--Concurrent-工具类介绍
并发编程--Concurrent-工具类介绍
- CountDownLatch
- CylicBarrier
- Semaphore
- Condition 对象监视器下个篇幅引入
- Callable 不单独说明 Demo中会使用
- Future
Java 5 添加了一个新的包到 Java 平台,java.util.concurrent 包
这个包包含有一系列能够让 Java 的并发编程变得更加简单轻松的类。在这个包被添加以前,你需要自己去动手实现自己的相关工具类;
- 本文我将带你一一认识 java.util.concurrent 包里的这些类,然后你可以尝试着如何在项目中使用它们。本文中我将使用 Java 6 版本,我不确定这和 Java 5 版本里的是否有一些差异
- 我不会去解释关于 Java 并发的核心问题 其背后的原理,也就是说,如果你对那些东西感兴趣,参考《Java 并发指南》;
1. CountDownLatch(计时器)
简介
官方介绍
- > A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.同步协助,允许一个或多个线程等待,直到其他一组线程执行的操作完成,再继续执行。
理解:
- CountDownLatch是一个同步的辅助类,它可以允许一个或多个线程等待,直到一组在其它线程中的操作执行完成。
- 一个CountDownLatch会通过一个给定的count数来被初始化。其中await()方法会一直阻塞,来作为一个开/关的门或门闩:直到当前的count被减到0,而这个过程是通过调用countDown()方法来实现的。在await()方法不再阻塞以后,所有等待的线程都会被释放,并且任何await()的子调用都会立刻返回。这是一次性的--count不能被重置。如果你需要一种能重置count的版本,请考虑使用CyclicBarrier。
- CountDownLatch一个有用的属性就是它不需要线程们在继续执行之前,调用countDown来等待count被减到0。它简单地阻止了任何调用了await()的线程继续,直到所有的线程都能够通过。
作用
个人理解:CountDownLatch:我把他理解成倒计时锁。
场景:常用于监听某些初始化操作,等待初始化操作完成后,通知主线程继续工作。
示例:MyCountDownLatch.Java
public class MyCountDownLatch { public static void main(String[] args) { final CountDownLatch countDown = new CountDownLatch(2); Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println("进入线程t1" + "等待其他线程处理完成...");
countDown.await();
System.out.println("t1线程继续执行...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"t1"); Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println("t2线程进行初始化操作...");
Thread.sleep(3000);
System.out.println("t2线程初始化完毕,通知t1线程继续...");
countDown.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println("t3线程进行初始化操作...");
Thread.sleep(4000);
System.out.println("t3线程初始化完毕,通知t1线程继续...");
countDown.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}); t1.start();
t2.start();
t3.start();
}
}
执行结果
进入线程t1等待其他线程处理完成...
t2线程进行初始化操作...
t3线程进行初始化操作...
t2线程初始化完毕,通知t1线程继续...
t3线程初始化完毕,通知t1线程继续...
t1线程继续执行...
2. CylicBarrier(栅栏)
CylicBarrier 的作用
- CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。
- CyclicBarrier默认的构造方法是CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。
个人理解:CyclicBarrier:可看成是个障碍,所有的线程必须到齐后才能一起通过这个障碍。
示例:
public class MyCyclicBarrier { static class Runner implements Runnable {
private CyclicBarrier barrier;
private String name; public Runner(CyclicBarrier barrier, String name) {
this.barrier = barrier;
this.name = name;
}
@Override
public void run() {
try {
Thread.sleep(1000 * (new Random()).nextInt(5));
System.out.println(new SimpleDateFormat("YYYY-HH-MM hh:dd:ss").format(new Date()) +" " + name + " 准备OK.");
barrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(name + " Go!!");
}
} public static void main(String[] args) throws IOException, InterruptedException {
CyclicBarrier barrier = new CyclicBarrier(3); //
ExecutorService executor = Executors.newFixedThreadPool(3); executor.submit(new Thread(new Runner(barrier, "zhangsan")));
executor.submit(new Thread(new Runner(barrier, "lisi")));
executor.submit(new Thread(new Runner(barrier, "wangwu"))); executor.shutdown();
} }
输出结果:
2018-02-06 02:30:06 lisi 准备OK.
2018-02-06 02:30:06 zhangsan 准备OK.
2018-02-06 02:30:07 wangwu 准备OK.
2018-02-06 02:30:07 wangwu Go!!
2018-02-06 02:30:07 lisi Go!!
2018-02-06 02:30:07 zhangsan Go!!
CyclicBarrier的应用场景
- CyclicBarrier可以用于多线程计算数据,最后合并计算结果的应用场景。
- 比如我们用一个Excel保存了用户所有银行流水,每个Sheet保存一个帐户近一年的每笔银行流水,现在需要统计用户的日均银行流水,先用多线程处理每个sheet里的银行流水,都执行完之后,得到每个sheet的日均银行流水,最后,再用barrierAction用这些线程的计算结果,计算出整个Excel的日均银行流水。
3. Semaphore(信号量)
Semaphore的作用
- 在java中,使用了synchronized关键字和Lock锁实现了资源的并发访问控制,在同一时间只允许唯一了线程进入临界区访问资源(读锁除外),这样子控制的主要目的是为了解决多个线程并发同一资源造成的数据不一致的问题。
- Semaphore主要是在多线程中可以轻松控制信号量,针对某个资源可被并发访问的个数。acquire()方法可以或得一个访问的许可,release()方法释放一个许可。提供同步机制,控制同时访问的个数。
示例:
public class MySemaphore {
public static void main(String[] args) {
// 线程池
ExecutorService exec = Executors.newCachedThreadPool();
// 只能2个线程同时访问
final Semaphore semp = new Semaphore(2);
// 模拟10个客户端访问
for (int index = 0; index < 10; index++) {
final int NO = index;
Runnable run = new Runnable() {
public void run() {
try {
// 获取许可
semp.acquire();
System.out.println(new SimpleDateFormat("YYYY-HH-MM hh:dd:ss").format(new Date()) +" " + "Accessing: " + NO);
//模拟实际业务逻辑
Thread.sleep((long) (Math.random() * 10000));
// 访问完后,释放
semp.release();
} catch (InterruptedException e) {
}
}
};
exec.execute(run);
} try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
} //System.out.println(semp.getQueueLength());
// 退出线程池
exec.shutdown();
}
}
执行结果:
2018-11-06 11:30:51 pool-1-thread-1接受服务: 0
2018-11-06 11:30:51 pool-1-thread-2接受服务: 1
2018-11-06 11:30:53 pool-1-thread-6接受服务: 5
2018-11-06 11:30:56 pool-1-thread-3接受服务: 2
2018-11-06 11:30:57 pool-1-thread-5接受服务: 4
2018-11-06 11:30:58 pool-1-thread-10接受服务: 9
2018-11-06 11:30:02 pool-1-thread-7接受服务: 6
2018-11-06 11:30:04 pool-1-thread-8接受服务: 7
2018-11-06 11:30:08 pool-1-thread-9接受服务: 8
2018-11-06 11:30:10 pool-1-thread-4接受服务: 3
4. Future简介
- 在Java中一般通过继承Thread类或者实现Runnable接口这两种方式来创建多线程,但是这两种方式都有个缺陷,就是不能在执行完成后获取执行的结果,因此Java 1.5之后提供了Callable和Future接口,通过它们就可以在任务执行完毕之后得到任务的执行结果。
- Future接口代表异步计算的结果,通过Future接口提供的方法可以查看异步计算是否执行完成,或者等待执行结果并获取执行结果,同时还可以取消执行。
- FutureTask一个可取消的异步计算,FutureTask 实现了Future的基本方法,提空 start cancel 操作,可以查询计算是否已经完成,并且可以获取计算的结果。结果只可以在计算完成之后获取,get方法会阻塞当计算没有完成的时候,一旦计算已经完成,那么计算就不能再次启动或是取消。
- FutureTask 可以用来包装一个 Callable 或是一个runnable对象。因为FurtureTask实现了Runnable方法,所以 FutureTask可以提交(submit)给Excutor执行(excution).。
FutureTask使用场景
FutureTask可用于异步获取执行结果或取消执行任务的场景。通过传入Runnable或者Callable的任务给FutureTask,直接调用其run方法或者放入线程池执行,之后可以在外部通过FutureTask的get方法异步获取执行结果,因此,FutureTask非常适合用于耗时的计算,主线程可以在完成自己的任务后,再去获取结果。另外,FutureTask还可以确保即使调用了多次run方法,它都只会执行一次Runnable或者Callable任务,或者通过cancel取消FutureTask的执行等.
public class MyFuture implements Callable<String>{
private String para; public MyFuture(String para){
this.para = para;
} /**
* 这里是真实的业务逻辑,其执行可能很慢
*/
@Override
public String call() throws Exception {
//模拟执行耗时
Thread.sleep(5000); //模拟耗时业务
String result = this.para + "处理完成";
return result;
} //主控制函数
public static void main(String[] args) throws Exception {
String queryStr = "query";
//构造FutureTask,并且传入需要真正进行业务逻辑处理的类,该类一定是实现了Callable接口的类
FutureTask<String> future = new FutureTask<String>(new MyFuture(queryStr)); FutureTask<String> future2 = new FutureTask<String>(new MyFuture(queryStr));
//创建一个固定线程的线程池且线程数为1,
ExecutorService executor = Executors.newFixedThreadPool(2);
//这里提交任务future,则开启线程执行RealData的call()方法执行
//submit和execute的区别: 第一点是submit可以传入实现Callable接口的实例对象, 第二点是submit方法有返回值 Future f1 = executor.submit(future); //单独启动一个线程去执行的
Future f2 = executor.submit(future2);
System.out.println(new SimpleDateFormat("YYYY-HH-MM hh:dd:ss").format(new Date()) +" " + "请求完毕"); try {
//这里可以做额外的数据操作,也就是主程序执行其他业务逻辑
System.out.println(new SimpleDateFormat("YYYY-HH-MM hh:dd:ss").format(new Date()) +" " + "处理实际的业务逻辑...");
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
// 可以取消异步任务
//future2.cancel(true); try {
// 阻塞,等待异步任务执行完毕-获取异步任务的返回值
//调用获取数据方法,如果call()方法没有执行完成,则依然会进行等待
System.out.println(new SimpleDateFormat("YYYY-HH-MM hh:dd:ss").format(new Date()) +" future1 " + "数据:" + future.get());
System.out.println(new SimpleDateFormat("YYYY-HH-MM hh:dd:ss").format(new Date()) +" future2" + "数据:" + future2.get()); } catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
executor.shutdown();
}
}
运行结构:
2018-11-06 11:30:38 请求完毕
2018-11-06 11:30:38 处理实际的业务逻辑...
2018-11-06 11:30:39 future1 数据:query处理完成
2018-11-06 11:30:43 future2数据:query处理完成
并发编程--Concurrent-工具类介绍的更多相关文章
- 并发编程常用工具类(一) countDownLatch和cyclicBarrier的使用对比
1.CountDownLatch countDownLatch的作用是让一组线程等待其他线程完成工作以后在执行,相当于加强版的join(不懂可以百度一下join的用法),一般在初始 ...
- java并发编程 - Exexctors 工具类
Executors 类提供了一系列静态工厂方法用于创建各种线程池. newFixedThreadPool 创建固定大小的线程池.每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小.线程池的大 ...
- 并发编程常用工具类(二) SymaPhore实现线程池
1.symaPhore简介 symaphore(信号量)用来控制同时访问某个资源的线程数量,一般用在并发流量控制.个人对它的理解相当于是接待室每次只能接待固定数量的人,当达到最高接待数的时候,其他人就 ...
- 并发编程(二)concurrent 工具类
并发编程(二)concurrent 工具类 一.CountDownLatch 经常用于监听某些初始化操作,等初始化执行完毕后,通知主线程继续工作. import java.util.concurren ...
- Java并发编程:Thread类的使用
Java并发编程:Thread类的使用 在前面2篇文章分别讲到了线程和进程的由来.以及如何在Java中怎么创建线程和进程.今天我们来学习一下Thread类,在学习Thread类之前,先介绍与线程相关知 ...
- 3、Java并发编程:Thread类的使用
Java并发编程:Thread类的使用 在前面2篇文章分别讲到了线程和进程的由来.以及如何在Java中怎么创建线程和进程.今天我们来学习一下Thread类,在学习Thread类之前,先介绍与线程相关知 ...
- Python并发编程-concurrent包
Python并发编程-concurrent包 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.concurrent.futures包概述 3.2版本引入的模块. 异步并行任务编程 ...
- 【转】Java并发编程:Thread类的使用
一.线程的状态 在正式学习Thread类中的具体方法之前,我们先来了解一下线程有哪些状态,这个将会有助于对Thread类中的方法的理解. 线程从创建到最终的消亡,要经历若干个状态.一般来说,线程包括以 ...
- Java语言Lang包下常用的工具类介绍_java - JAVA
文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 无论你在开发哪中 Java 应用程序,都免不了要写很多工具类/工具函数.你可知道,有很多现成的工具类可用,并且代码质量都 ...
随机推荐
- MySQL性能优化(二):优化数据库的设计
原文:MySQL性能优化(二):优化数据库的设计 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.n ...
- java 问题汇总
1.自动加载出错 require a bean of .... The injection point has the following annotations: - @org.springfram ...
- VS Code 配置碰到的问题
VS Code 呈现缩进参考线以及语法高亮改变 找到 首选项——>设置→搜索renderIntentGuides→将此选项改为true(默认为false),就可以了.
- 099、如何访问Service (Swarm06)
参考https://www.cnblogs.com/CloudMan6/p/7909136.html 前面已经学习了如何部署Service吗,也验证了swarm的failover特性,下面我们要学 ...
- 关于redis的几件小事(五)redis保证高并发以及高可用
如果你用redis缓存技术的话,肯定要考虑如何用redis来加多台机器,保证redis是高并发的,还有就是如何让Redis保证自己不是挂掉以后就直接死掉了,redis高可用 redis高并发:主从架构 ...
- Hyperledger Fabric(3)通道与组织
1,通道的结构 通道是Fabric中非常重要的概念(类似微信群?),它实质是由排序节点划分和管理的私有原子广播通道,目的是对通道的信息进行隔离,使得通道外的实体无法访问通道内的信息,从而实现交易的隐私 ...
- 自己实现一个简化版的SpringMVC框架
废话不多说,我们进入今天的正题,在Web应用程序设计中,MVC模式已经被广泛使用.SpringMVC以DispatcherServlet为核心,负责协调和组织不同组件以完成请求处理并返回响应的工作,实 ...
- 从FBV到CBV三(权限)
丛FBC到CBV三(权限) span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0 ...
- zzu edu
https://jw.v.zzu.edu.cn/eams/login.action 查询密码: 身份证后六位
- js - 执行上下文和作用域以及闭包
首先,咱们通常被"执行上下文","执行上下文环境","上下文环境","执行上下文栈"这些名词搞混.那我们一一来揭秘这些名 ...