java 5线程中 Semaphore信号灯,CyclicBarrier类,CountDownLatch计数器以及Exchanger类使用
先来讲解一下Semaphore信号灯的作用:
可以维护当前访问自身的线程个数,并提供了同步机制,
使用semaphore可以控制同时访问资源的线程个数
例如,实现一个文件允许的并发访问数。
请看下面的演示代码:
public class SemaphoreTest
{
public static void main(String[] args)
{
//创建一个带有缓存的线程池
ExecutorService service = Executors.newCachedThreadPool();
//创建三个信号灯
final Semaphore sp = new Semaphore(3);//最多并发三个线程 此处可以按照需求去修改
//开启十个线程
for (int i = 1; i <= 10; i++)
{
//只有三个线程可以同时进入 其余线程等待
service.execute(new Runnable()
{
@Override
public void run()
{
try
{
sp.acquire();//获取一盏信号灯
} catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println("线程 "+Thread.currentThread().getName()+" 进入"
+ " ,当前已有 "+(3-sp.availablePermits())+ " 个并发");
try
{
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e)
{
e.printStackTrace();
}
System.out.println("线程 "+Thread.currentThread().getName()+" 即将离开 ");
sp.release();//释放
System.out.println("线程 "+Thread.currentThread().getName()+" 已经离开"
+ " ,当前已有 "+(3-sp.availablePermits())+ " 个并发");
}
});
}
service.shutdown();
}
}
执行结果如下:
线程 pool-1-thread-2 进入 ,当前已有 2 个并发
线程 pool-1-thread-3 进入 ,当前已有 3 个并发
线程 pool-1-thread-1 进入 ,当前已有 3 个并发
线程 pool-1-thread-3 即将离开
线程 pool-1-thread-3 已经离开 ,当前已有 2 个并发
线程 pool-1-thread-4 进入 ,当前已有 3 个并发
线程 pool-1-thread-1 即将离开
线程 pool-1-thread-5 进入 ,当前已有 3 个并发
线程 pool-1-thread-1 已经离开 ,当前已有 3 个并发
线程 pool-1-thread-2 即将离开
线程 pool-1-thread-2 已经离开 ,当前已有 2 个并发
线程 pool-1-thread-6 进入 ,当前已有 3 个并发
线程 pool-1-thread-6 即将离开
线程 pool-1-thread-6 已经离开 ,当前已有 2 个并发
线程 pool-1-thread-7 进入 ,当前已有 3 个并发
线程 pool-1-thread-7 即将离开
线程 pool-1-thread-7 已经离开 ,当前已有 2 个并发
线程 pool-1-thread-8 进入 ,当前已有 3 个并发
线程 pool-1-thread-4 即将离开
线程 pool-1-thread-4 已经离开 ,当前已有 2 个并发
线程 pool-1-thread-9 进入 ,当前已有 3 个并发
线程 pool-1-thread-5 即将离开
线程 pool-1-thread-5 已经离开 ,当前已有 2 个并发
线程 pool-1-thread-10 进入 ,当前已有 3 个并发
线程 pool-1-thread-10 即将离开
线程 pool-1-thread-10 已经离开 ,当前已有 2 个并发
线程 pool-1-thread-8 即将离开
线程 pool-1-thread-8 已经离开 ,当前已有 1 个并发
线程 pool-1-thread-9 即将离开
线程 pool-1-thread-9 已经离开 ,当前已有 0 个并发
Semaphore信号灯可以控制并发数,保证每次最多只能有三个线程在线程池中。
CyclicBarrier类的使用,可以模拟现实生活中的多人等待上车的情形,例如多人去旅行,那么当A到达集合点时,不能立即出发,必须等到B也到达集合点,那么A和B必须等到C也到达集合点,此时,三人可以坐车出发去下一站。该类就可以实现此功能,请看如下代码。
public class CyclicBarrierTest
{
public static void main(String[] args)
{
//创建一个带有缓存的线程池
ExecutorService service = Executors.newCachedThreadPool();
//指定三个线程 只有当三个线程同时到达时 程序才会往下执行
final CyclicBarrier cb = new CyclicBarrier(3); for (int i = 0; i < 3; i++)
{
Runnable runnable = new Runnable()
{
@Override
public void run()
{
try
{
/**
* cb.getNumberWaiting():从0开始,获取当前等待的线程数量
*/
//第一个
Thread.sleep(new Random().nextInt(1000));
System.out.println("线程 "+Thread.currentThread().getName()+" 即将到达集合地点1,"
+ "当前已有"+(cb.getNumberWaiting()+1)+" 个线程,"+(cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在继续等待"));
cb.await();//让线程等待 //第二个
Thread.sleep(new Random().nextInt(1000));
System.out.println("线程 "+Thread.currentThread().getName()+" 即将到达集合地点2,"
+ "当前已有"+(cb.getNumberWaiting()+1)+" 个线程,"+(cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在继续等待"));
cb.await(); //第三个
Thread.sleep(new Random().nextInt(1000));
System.out.println("线程 "+Thread.currentThread().getName()+" 即将到达集合地点3,"
+ "当前已有"+(cb.getNumberWaiting()+1)+" 个线程,"+(cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在继续等待"));
cb.await();
} catch (InterruptedException | BrokenBarrierException e)
{
e.printStackTrace();
}
}
};
service.execute(runnable);
} service.shutdown();//关闭线程池
}
}
如下是执行结果:
线程 pool-1-thread-2 即将到达集合地点1,当前已有1 个线程,正在继续等待
线程 pool-1-thread-1 即将到达集合地点1,当前已有2 个线程,正在继续等待
线程 pool-1-thread-3 即将到达集合地点1,当前已有3 个线程,都到齐了,继续走啊
线程 pool-1-thread-2 即将到达集合地点2,当前已有1 个线程,正在继续等待
线程 pool-1-thread-1 即将到达集合地点2,当前已有2 个线程,正在继续等待
线程 pool-1-thread-3 即将到达集合地点2,当前已有3 个线程,都到齐了,继续走啊
线程 pool-1-thread-1 即将到达集合地点3,当前已有1 个线程,正在继续等待
线程 pool-1-thread-2 即将到达集合地点3,当前已有2 个线程,正在继续等待
线程 pool-1-thread-3 即将到达集合地点3,当前已有3 个线程,都到齐了,继续走啊
CountDownLatch计数器的使用:
* 演示一个计数器CountDownLatch
* 模拟百米赛跑
* 1个裁判 吹口哨
* 3个运动员
public class CountDownLatchTest
{
public static void main(String[] args)
{
//创建一个带有缓存的线程池
ExecutorService service = Executors.newCachedThreadPool();
final CountDownLatch cdOrder = new CountDownLatch(1);//裁判
final CountDownLatch cdAnswer = new CountDownLatch(3);//运动员
for (int i = 0; i < 3; i++)
{
Runnable runnable = new Runnable()
{
@Override
public void run()
{
try
{
System.out.println("线程"+Thread.currentThread().getName()+" 正准备接收命令 ");
cdOrder.await();//等待计数器归0时 代码向下走
System.out.println("线程"+Thread.currentThread().getName()+" 已接收命令 ");
Thread.sleep(new Random().nextInt(1000));
System.out.println("线程"+Thread.currentThread().getName()+" 回应命令处理结果 ");
cdAnswer.countDown();//没调用一次该方法 就会将当前计数器上的计数减1
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
};
service.execute(runnable);
} //主线恒
try
{
Thread.sleep(new Random().nextInt(1000));
System.out.println("线程"+Thread.currentThread().getName()+" 即将发布命令 ");
cdOrder.countDown();//相当于把计数器身上的计数减1
System.out.println("线程"+Thread.currentThread().getName()+" 已发送命令,正在等待结果 ");
cdAnswer.await();
System.out.println("线程"+Thread.currentThread().getName()+" 已收到所有相应结果");
} catch (InterruptedException e)
{
e.printStackTrace();
}
service.shutdown();//关闭线程池
}
}
如下是执行结果:
线程pool-1-thread-1 正准备接收命令
线程pool-1-thread-2 正准备接收命令
线程pool-1-thread-3 正准备接收命令
线程main 即将发布命令
线程main 已发送命令,正在等待结果
线程pool-1-thread-1 已接收命令
线程pool-1-thread-2 已接收命令
线程pool-1-thread-3 已接收命令
线程pool-1-thread-2 回应命令处理结果
线程pool-1-thread-3 回应命令处理结果
线程pool-1-thread-1 回应命令处理结果
线程main 已收到所有相应结果
Exchanger类可以实现两个线程之间的数据交换:
public class ExchangerTest
{
public static void main(String[] args)
{
//创建一个带有缓存的线程池
ExecutorService service = Executors.newCachedThreadPool();
final Exchanger<String> changer = new Exchanger<String>();
//开启第一个任务
service.execute(new Runnable()
{
@Override
public void run()
{
try
{
String dtail1 = "zhangsan";//准备要交换出去的数据
System.out.println("线程 "+Thread.currentThread().getName()+" 正要把"+dtail1+"换出去");
Thread.sleep(new Random().nextInt(1000));
String dtail2 = changer.exchange(dtail1);//换回来的数据
System.out.println("线程 "+Thread.currentThread().getName()+"换回的数据为"+dtail2);
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}); //开启第二个任务
service.execute(new Runnable()
{
@Override
public void run()
{
try
{
String dtail1 = "lisi";//准备要交换出去的数据
System.out.println("线程 "+Thread.currentThread().getName()+" 正要把"+dtail1+"换出去");
Thread.sleep(new Random().nextInt(1000));
String dtail2 = changer.exchange(dtail1);//换回来的数据
System.out.println("线程 "+Thread.currentThread().getName()+"换回的数据为"+dtail2);
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
});
service.shutdown();
}
}
如下是执行结果:
线程 pool-1-thread-1 正要把zhangsan换出去
线程 pool-1-thread-2 正要把lisi换出去
线程 pool-1-thread-1换回的数据为lisi
线程 pool-1-thread-2换回的数据为zhangsan
以上都是java 5中的一些知识点,大家可以根据实际工作中的需要进行选择使用!!
java 5线程中 Semaphore信号灯,CyclicBarrier类,CountDownLatch计数器以及Exchanger类使用的更多相关文章
- Android进阶——多线程系列之Semaphore、CyclicBarrier、CountDownLatch
今天向大家介绍的是多线程开发中的一些辅助类,他们的作用无非就是帮助我们让多个线程按照我们想要的执行顺序来执行.如果我们按照文字来理解Semaphore.CyclicBarrier.CountDownL ...
- java的线程中的Runnable
在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口:Thread类是在java.lang包中定义的.一个类只要继承了Thr ...
- Java子线程中的异常处理(通用)
在普通的单线程程序中,捕获异常只需要通过try ... catch ... finally ...代码块就可以了.那么,在并发情况下,比如在父线程中启动了子线程,如何正确捕获子线程中的异常,从而进行相 ...
- Java子线程中操作主线程Private级别数据
两个类分别如下: <pre name="code" class="java">package Demo2; import java.util.*; ...
- 转:Java子线程中的异常处理(通用)
引自:https://www.cnblogs.com/yangfanexp/p/7594557.html 在普通的单线程程序中,捕获异常只需要通过try ... catch ... finally . ...
- JAVA多线程提高十:同步工具CyclicBarrier与CountDownLatch
今天继续学习其它的同步工具:CyclicBarrier与CountDownLatch 一.CyclicBarrier CyclicBarrier是一个同步辅助类,它允许一组线程互相等待,直到到达某个公 ...
- JUC-JUC强大的辅助类讲解(Semaphore、CyclicBarrier、CountDownLatch)
一.CountDownLatch 减少计数 1.原理 * CountDownLatch主要有两个方法,当一个或多个线程调用await方法时,这些线程会阻塞. * 其它线程调用countDown方法会将 ...
- JAVA多线程学习十三 - 同步工具CyclicBarrier与CountDownLatch
一.CyclicBarrier CyclicBarrier是一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point).在涉及一组固定大小的线程的程序 ...
- Java并发包中Semaphore的工作原理、源码分析及使用示例
1. 信号量Semaphore的介绍 我们以一个停车场运作为例来说明信号量的作用.假设停车场只有三个车位,一开始三个车位都是空的.这时如果同时来了三辆车,看门人允许其中它们进入进入,然后放下车拦.以后 ...
随机推荐
- 【Luogu3919】可持久化数组(主席树)
题面戳我 题解 放一个板子在这里 用主席树维护一下每个版本就可以啦... #include<iostream> #include<cstdio> #include<cst ...
- JavaScript的基本操作(一)
JavaScript中有大量的方法可供我们使用,详情可参考:http://jquery.cuishifeng.cn/这也同时导致我们不可能去记住每一个的用法,且开发者每天都在新添更多的方法,所以要想掌 ...
- wpf研究之道-grid控件
想要说些什么,却不知道从哪开始."形而上谓之道,形而下谓之器".与其坐而论道,不如脚踏实地,从最实用的地方开始. 我们先来看看wpf中的grid控件.grid控件是个网格的布局控件 ...
- sprintf函数使用
功能 把格式化的数据写入某个字符缓冲区. 所需头文件 stdio.h 原型 int sprintf( char *buffer, const char *format, [ argument] - ) ...
- 云计算之路-阿里云上:针对 docker swarm 故障的部署调整以及应急措施
针对这周 docker swarm 集群的频繁故障(详见故障一 .故障二.故障三),我们今天对 docker swarm 集群的部署进行了如下调整. 将 docker engine 由 “17.12 ...
- Cannot find class: BaseResultMap
版权声明:本文为博主原创文章,转载请注明出处. model对应的mapping中将resultType改成resultMap即可. 什么是相应的model的xml配置文件呢? 可以理解为: 一直都可以 ...
- NYOJ街区最短路径问题
描述 一个街区有很多住户,街区的街道只能为东西.南北两种方向. 住户只可以沿着街道行走. 各个街道之间的间隔相等. 用(x,y)来表示住户坐在的街区. 例如(4,20),表示用户在东西方向第4个街道, ...
- WordPress添加显示和隐藏侧边栏按钮开关
在很多的地方都看见过这种效果,就是在文章页面可以切换显示和隐藏侧边栏功能,感觉还是很有用,比如一篇文章的文字内容过多,那么就可以通过隐藏侧边栏来显示更多的文字便于浏览.比如你可以通过点击我文章标题下方 ...
- php做的一个简易爬虫
对于爬虫的好奇好像由来已久,一直在研究python的爬虫,今天得空研究研究php的爬虫 index.php <?php header("Content-Type:text/html;c ...
- tcpdump抓包工具的使用
个人原创,转载请注明,否则依法追究法律责任 2018-02-28 16:01:26 tcpdump 倾倒网络传输数据,直接启动tcpdump将监视第一个网络接口上所有流过的数据包. 1 不接任何参数 ...