Concurrent包工具类使用
一。读写锁
传统的同步锁就是独占式锁,当线程使用资源时候保持独占,无论读写。当人们发现请求队列(假设)中相邻请求为读-读的时候,阻塞是一种浪费资源的操作。比如公告板,所有路过的人(请求)都是读操作,并没有因为你和他在读的时候对内容造成了改变,所以在模型中,读与读操作不需要阻塞。而读写相邻则需要进行独占式操作了,因为写未完成的时候,信息是不完整的,此时读出来的信息有可能是错误的,所以写必然要保持独占式操作。而在应用程序中,读的频率是写的好几倍,也就是说如果读-读是不阻塞的,那么对性能来说是毋庸置疑的提升。
Java中存在一种锁,名曰:ReentrantReadWriteLock。他可以实现内存中对资源操作的读写锁,读与读是不阻塞的。
import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; /**
* Created by MacBook on 2018/3/10.
*/
public class ReadWriteLockDemo {
private static Lock relock = new ReentrantLock();
private static ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private static Lock readLock = readWriteLock.readLock();
private static Lock writeLock = readWriteLock.writeLock();
private int value;
public Object handleRead(Lock lock) throws Exception{
try{
lock.lock();
Thread.sleep(1000);
return value;
}finally {
lock.unlock();
}
}
public void handleWrite(Lock lock,int index) throws Exception{
try{
lock.lock();
Thread.sleep(1000);
value = index;
}finally {
lock.unlock();
}
}
public static void main(String[] args){
ReadWriteLockDemo demo = new ReadWriteLockDemo();
Runnable readThread = new Runnable() {
@Override
public void run() {
try{
System.out.println("read:"+demo.handleRead(readLock));
}catch (Exception e){
e.printStackTrace();
}
}
};
Runnable writeThread = new Runnable() {
@Override
public void run() {
try{
// demo.handleWrite(relock,new Random().nextInt());
demo.handleWrite(writeLock,new Random().nextInt());
System.out.println("id:"+Thread.currentThread().getId()+" done!");
}catch (Exception e){
e.printStackTrace();
}
}
};
for(int i=0;i<18;i++){
new Thread(readThread).start();
}
for(int i=0;i<18;i++){
new Thread(writeThread).start();
}
} }
此demo使用了重入锁和读写锁的对比,在主程序中分别新建18个读写操作,如果使用了读操作,则打印的读操作是连续的;如果使用了重入锁,则可能的情况是读写相邻打印,并且都是阻塞的,读者可以自行测试体会。
二。对象监视器Condition
在JDK实现了Lock来简化synchronized之后,Condition作为简化监视器而存在。Condition的await方法和signal方法对应对象的wait和signal。
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock; /**
* Created by MacBook on 2018/3/10.
*/
public class ConditionAndLock implements Runnable{
static ReentrantLock lock = new ReentrantLock();
static Condition condition = lock.newCondition(); public void run(){
try{
lock.lock();
condition.await();
System.out.println("thread is running");
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public static void main(String[] args){
ConditionAndLock c = new ConditionAndLock();
Thread t = new Thread(c);
t.start();
lock.lock();
System.out.println("signal all");
condition.signalAll();
lock.unlock();
}
}
三。倒计时器CountDownLatch
多线程中,需要知道这批线程的最大完成任务时间,也就是从第一个任务开始到最后返回这段时间的时长,那么倒计时器是必不可少的。就像各项资源准备完毕才进行下一步操作的模型一样,CountDownLatch就是这样的多线程模型。等到所有任务调用了计数器,并且计数器总数到达某个数量时候,它才会将阻塞代码放开,让主线程往下走。
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; /**
* 倒计时器
* Created by MacBook on 2018/3/10.
*/
public class CountDownLatchDemo implements Runnable{
static CountDownLatch end = new CountDownLatch(10);
static CountDownLatchDemo demo = new CountDownLatchDemo();
public void run(){
try{
Thread.sleep(new Random().nextInt(10)*1000);
System.out.println(Thread.currentThread().getId()+" check complete!");
end.countDown();
}catch (Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception{
ExecutorService service = Executors.newFixedThreadPool(10);
for(int i=0;i<10;i++){
service.submit(demo);
}
end.await();
System.out.println("fire");
service.shutdown();
}
}
await方法是阻塞倒计时器所在线程的方法,等到线程池service中调用countDown方法到达一定的数量(此处是10)之后,主线程的await方法才会过去。
四。信号量
信号量这个东西就比较玄乎了,有点像准入许可,拿到信号准入的时候才往下执行。就像是有一批人拿号,只有号码区间在某个范围的人能进去办事,然后办完事就会让资源释放,号码区间往后移。然而在信号量中应该算是复用类型的,归还了key值,将key值返回给下一个申请者。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore; /**
* Created by MacBook on 2018/3/10.
*/
public class SemapDemo implements Runnable{
final Semaphore semp = new Semaphore(5);
public void run(){
try{
semp.acquire();
Thread.sleep(2000);
System.out.println(Thread.currentThread().getId()+" done!");
semp.release();
}catch (Exception e){
e.printStackTrace();
}
}
public static void main(String[] args){
ExecutorService executorService = Executors.newFixedThreadPool(5);
SemapDemo semapDemo = new SemapDemo();
for(int i=0;i<20;i++){
executorService.submit(semapDemo);
}
executorService.shutdown();
}
}
在acquire获得key之后,操作读写,之后release。
五。栅栏
栅栏和倒计时器很像,就是拦住一堆线程,等到线程数达到某个设定值之后同时把它们放出去。但是不同的是,它可以每次设定值达成时候运行定制线程中的run方法。就像是每次一个栏,够数就放。
import java.util.Random;
import java.util.concurrent.CyclicBarrier; /**
* Created by MacBook on 2018/3/10.
*/
public class CylicBarrierDemo {
public static class Soldier implements Runnable{
private String soldier;
private final CyclicBarrier cyclicBarrier;
Soldier(String soldier,CyclicBarrier cyclicBarrier){
this.soldier = soldier;
this.cyclicBarrier = cyclicBarrier;
}
public void run(){
try{
cyclicBarrier.await();
doWork();
cyclicBarrier.await();
}catch (Exception e){
e.printStackTrace();
}
}
public void doWork(){
try{
Thread.sleep(Math.abs(new Random().nextInt()%10000));
}catch (Exception e){
e.printStackTrace();
}
System.out.println(soldier + " done!");
}
}
public static class BarrierRun implements Runnable{
boolean flag;
int n;
public BarrierRun(boolean flag,int n){
this.flag = flag;
this.n = n;
} public void run(){
if(flag){
System.out.println("士兵:"+n+"个 done!");
}else {
System.out.println("士兵:"+n+"个 集合完毕!");
flag = true;
}
}
}
public static void main(String[] args){
final int n = 10;
Thread[] allSoldier = new Thread[n];
boolean flag = false;
CyclicBarrier cyclic = new CyclicBarrier(n,new BarrierRun(flag,n));
System.out.println("集合");
for(int i =0; i < n ; i++){
System.out.println("士兵 "+i+" 报道");
allSoldier[i] = new Thread(new Soldier("士兵"+i,cyclic));
allSoldier[i].start();
}
}
}
例中CyclicBarrier有两个参数,前一个就是提到的设定值,后一个就是定制线程了。每当到达设定值的时候会触发定制线程。

每个阶段完成都会调用一下定制线程。
六。LockSupport提供线程挂起操作的支持类
正如Condition使得原有的Object监视器封装成了新类,LockSupport提供使线程park和unpark之类的操作。
import java.util.concurrent.locks.LockSupport; /**
* Created by MacBook on 2018/3/10.
*/
public class LockSupportDemo {
public static Object u = new Object();
static ChangeObjectThread t1 = new ChangeObjectThread("t1");
static ChangeObjectThread t2 = new ChangeObjectThread("t2");
public static class ChangeObjectThread extends Thread{
public ChangeObjectThread(String name){
super.setName(name);
}
public void run(){
synchronized (u){
System.out.println("in "+getName());
LockSupport.park();
}
}
}
public static void main(String[] args) throws Exception{
t1.start();
Thread.sleep(100);
t2.start();
LockSupport.unpark(t1);
LockSupport.unpark(t2);
t1.join();
t2.join();
} }
它在park时候线程会变成wait状态,而不是runnable。
来自《Java高并发程序设计》的读书笔记
Concurrent包工具类使用的更多相关文章
- 常用Concurrent.util包工具类——高并发
一 Concurrent.util常用类: 1. CyclicBarrier: 假设有场景:每个线程代表一个跑步运动员,当运动员都准备好后,才一起出发只要有一个人没有准备好,大家都等待. import ...
- Java 操作jar包工具类以及如何快速修改Jar包里的文件内容
需求背景:写了一个实时读取日志文件以及监控的小程序,打包成了Jar包可执行文件,通过我们的web主系统上传到各个服务器,然后调用ssh命令执行.每次上传前都要通过解压缩软件修改或者替换里面的配置文件, ...
- 高并发编程基础(java.util.concurrent包常见类基础)
JDK5中添加了新的java.util.concurrent包,相对同步容器而言,并发容器通过一些机制改进了并发性能.因为同步容器将所有对容器状态的访问都串行化了,这样保证了线程的安全性,所以这种方法 ...
- Java操作FTP工具类(实例详解)
这里使用Apache的FTP jar 包 没有使用Java自带的FTPjar包 工具类 package com.zit.ftp; import java.io.File; import java.i ...
- C#中SQLite的使用及工具类
目录 SQLite简介 存储类 亲和类型 引用System.Data.SQLite.dll 软件包分类 使用本机库预加载 常用部署包 工具类 参考资料 SQLite简介 SQLite是一款轻型的数据库 ...
- 并发之java.util.concurrent.atomic原子操作类包
15.JDK1.8的Java.util.concurrent.atomic包小结 14.Java中Atomic包的原理和分析 13.java.util.concurrent.atomic原子操作类包 ...
- 推荐使用concurrent包中的Atomic类
这是一个真实案例,曾经惹出硕大风波,故事的起因却很简单,就是需要实现一个简单的计数器,每次取值然后加1,于是就有了下面这段代码: private int counter = ...
- JUC 包下工具类,它的名字叫 LockSupport !你造么?
前言 LockSupport 是 JUC 中常用的一个工具类,主要作用是挂起和唤醒线程.在阅读 JUC 源码中经常看到,所以很有必要了解一下. 公众号:liuzhihangs ,记录工作学习中的技术. ...
- 代码片段:基于 JDK 8 time包的时间工具类 TimeUtil
摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢! “知识的工作者必须成为自己时间的首席执行官.” 前言 这次泥瓦匠带来的是一个好玩的基于 JDK ...
随机推荐
- git 记住用户名和密码
git 记住用户名和密码 在使用 git 时,如果用的是 HTTPS 的方式,则每次提交,都会让输入用户名和密码,久而久之,就会感觉非常麻烦,那么该如何解决呢? 1. 使用 SSH,添加 ssh ke ...
- mybatis 传参为 Integer 时 ,Mapper 文件 中判断 条件 问题。
<if test="valiStatus==null || valiStatus=='' || valiStatus==4 "> b.work_permit_card_ ...
- pandas replace函数使用小结
http://blog.csdn.net/kancy110/article/details/72719340
- 客户被绑,蒙眼,惊问:“想干什么?” 对方不语,鞭笞之,客户求饶:“别打,要钱?” 又一鞭,“十万够不?” 又一鞭,“一百万?” 又一鞭。客户崩溃:“你们TMD到底要啥?” “要什么?...
1. 客户被绑,蒙眼,惊问:“想干什么?” 对方不语,鞭笞之,客户求饶:“别打,要钱?” 又一鞭,“十万够不?” 又一鞭,“一百万?” 又一鞭.客户崩溃:“你们TMD ...
- 2018.09.15 bzoj1977:次小生成树 Tree(次小生成树+树剖)
传送门 一道比较综合的好题. 由于是求严格的次小生成树. 我们需要维护一条路径上的最小值和次小值. 其中最小值和次小值不能相同. 由于不喜欢倍增我选择了用树链剖分维护. 代码: #include< ...
- java NIO编程(转)
一.概念 在传统的java网络编程中,都是在服务端创建一个ServerSocket,然后为每一个客户端单独创建一个线程Thread分别处理各自的请求,由于对于CPU而言,线程的开销是很大的,无限创建线 ...
- scanf和fscanf读取文件
这篇是针对推箱子游戏而写的,某个时候在学C语言,最近转到windows设计,不知道是否有同样的感受,后面的东西学了,前面的就有点生疏了.其实,我的理解是,注意力转移了,当集中于当前问题的时候就会忽略以 ...
- 数据分析工具R和RStudio入门介绍
https://www.cnblogs.com/yjd_hycf_space/p/6672995.html Python&R语言-python和r相遇:https://www.cnblogs. ...
- hdu 5685 Problem A (逆元)
题目 题意:H(s)=∏i≤len(s)i=1(Si−28) (mod 9973),求一个字符串 子串(a 位到 b 位的)的哈希值.这个公式便是求字符串哈希值的公式,(字符的哈希值 = 字符的ASC ...
- Keil5编译STM32注意事项
硬件:某STM32开发板,ST-Link/V2 一.硬件相关: 1.引脚连接: pin7 <-> SWIO pin9 <-> SWCLK pin20/pin18 <-&g ...