java 5线程中 Semaphore信号灯,CyclicBarrier类,CountDownLatch计数器以及Exchanger类使用

先来讲解一下Semaphore信号灯的作用:

 可以维护当前访问自身的线程个数,并提供了同步机制,

使用semaphore可以控制同时访问资源的线程个数

例如,实现一个文件允许的并发访问数。

请看下面的演示代码:

 1 public class SemaphoreTest
 2 {
 3     public static void main(String[] args)
 4     {
 5         //创建一个带有缓存的线程池
 6         ExecutorService service = Executors.newCachedThreadPool();
 7         //创建三个信号灯
 8         final Semaphore sp = new Semaphore(3);//最多并发三个线程  此处可以按照需求去修改
 9         //开启十个线程
10         for (int i = 1; i <= 10; i++)
11         {
12             //只有三个线程可以同时进入    其余线程等待
13             service.execute(new Runnable()
14             {
15                 @Override
16                 public void run()
17                 {
18                     try
19                     {
20                         sp.acquire();//获取一盏信号灯
21                     } catch (InterruptedException e)
22                     {
23                         e.printStackTrace();
24                     }
25                     System.out.println("线程 "+Thread.currentThread().getName()+" 进入"
26                             + " ,当前已有 "+(3-sp.availablePermits())+ " 个并发");
27                     try
28                     {
29                         Thread.sleep(new Random().nextInt(1000));
30                     } catch (InterruptedException e)
31                     {
32                         e.printStackTrace();
33                     }
34                     System.out.println("线程 "+Thread.currentThread().getName()+" 即将离开 ");
35                     sp.release();//释放
36                     System.out.println("线程 "+Thread.currentThread().getName()+" 已经离开"
37                             + " ,当前已有 "+(3-sp.availablePermits())+ " 个并发");
38                 }
39             });
40         }
41         service.shutdown();
42     }
43 }

执行结果如下:

线程 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也到达集合点,此时,三人可以坐车出发去下一站。该类就可以实现此功能,请看如下代码。

 1 public class CyclicBarrierTest
 2 {
 3     public static void main(String[] args)
 4     {
 5         //创建一个带有缓存的线程池
 6         ExecutorService service = Executors.newCachedThreadPool();
 7         //指定三个线程 只有当三个线程同时到达时 程序才会往下执行
 8         final CyclicBarrier cb = new CyclicBarrier(3);
 9
10         for (int i = 0; i < 3; i++)
11         {
12             Runnable runnable = new Runnable()
13             {
14                 @Override
15                 public void run()
16                 {
17                     try
18                     {
19                         /**
20                          * cb.getNumberWaiting():从0开始,获取当前等待的线程数量
21                          */
22                         //第一个
23                         Thread.sleep(new Random().nextInt(1000));
24                         System.out.println("线程 "+Thread.currentThread().getName()+" 即将到达集合地点1,"
25                                 + "当前已有"+(cb.getNumberWaiting()+1)+" 个线程,"+(cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在继续等待"));
26                         cb.await();//让线程等待
27
28                         //第二个
29                         Thread.sleep(new Random().nextInt(1000));
30                         System.out.println("线程 "+Thread.currentThread().getName()+" 即将到达集合地点2,"
31                                 + "当前已有"+(cb.getNumberWaiting()+1)+" 个线程,"+(cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在继续等待"));
32                         cb.await();
33
34                         //第三个
35                         Thread.sleep(new Random().nextInt(1000));
36                         System.out.println("线程 "+Thread.currentThread().getName()+" 即将到达集合地点3,"
37                                 + "当前已有"+(cb.getNumberWaiting()+1)+" 个线程,"+(cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在继续等待"));
38                         cb.await();
39                     } catch (InterruptedException | BrokenBarrierException e)
40                     {
41                         e.printStackTrace();
42                     }
43                 }
44             };
45             service.execute(runnable);
46         }
47
48         service.shutdown();//关闭线程池
49     }
50 }

如下是执行结果:

1 线程 pool-1-thread-2 即将到达集合地点1,当前已有1 个线程,正在继续等待
2 线程 pool-1-thread-1 即将到达集合地点1,当前已有2 个线程,正在继续等待
3 线程 pool-1-thread-3 即将到达集合地点1,当前已有3 个线程,都到齐了,继续走啊
4 线程 pool-1-thread-2 即将到达集合地点2,当前已有1 个线程,正在继续等待
5 线程 pool-1-thread-1 即将到达集合地点2,当前已有2 个线程,正在继续等待
6 线程 pool-1-thread-3 即将到达集合地点2,当前已有3 个线程,都到齐了,继续走啊
7 线程 pool-1-thread-1 即将到达集合地点3,当前已有1 个线程,正在继续等待
8 线程 pool-1-thread-2 即将到达集合地点3,当前已有2 个线程,正在继续等待
9 线程 pool-1-thread-3 即将到达集合地点3,当前已有3 个线程,都到齐了,继续走啊

CountDownLatch计数器的使用:

* 演示一个计数器CountDownLatch

* 模拟百米赛跑

* 1个裁判 吹口哨

* 3个运动员

 1 public class CountDownLatchTest
 2 {
 3     public static void main(String[] args)
 4     {
 5         //创建一个带有缓存的线程池
 6         ExecutorService service = Executors.newCachedThreadPool();
 7         final CountDownLatch cdOrder = new CountDownLatch(1);//裁判
 8         final CountDownLatch cdAnswer = new CountDownLatch(3);//运动员
 9         for (int i = 0; i < 3; i++)
10         {
11             Runnable runnable = new Runnable()
12             {
13                 @Override
14                 public void run()
15                 {
16                     try
17                     {
18                         System.out.println("线程"+Thread.currentThread().getName()+" 正准备接收命令 ");
19                         cdOrder.await();//等待计数器归0时 代码向下走
20                         System.out.println("线程"+Thread.currentThread().getName()+" 已接收命令 ");
21                         Thread.sleep(new Random().nextInt(1000));
22                         System.out.println("线程"+Thread.currentThread().getName()+" 回应命令处理结果  ");
23                         cdAnswer.countDown();//没调用一次该方法 就会将当前计数器上的计数减1
24                     } catch (InterruptedException e)
25                     {
26                         e.printStackTrace();
27                     }
28                 }
29             };
30             service.execute(runnable);
31         }
32
33
34         //主线恒
35         try
36         {
37             Thread.sleep(new Random().nextInt(1000));
38             System.out.println("线程"+Thread.currentThread().getName()+" 即将发布命令 ");
39             cdOrder.countDown();//相当于把计数器身上的计数减1
40             System.out.println("线程"+Thread.currentThread().getName()+" 已发送命令,正在等待结果   ");
41             cdAnswer.await();
42             System.out.println("线程"+Thread.currentThread().getName()+" 已收到所有相应结果");
43         } catch (InterruptedException e)
44         {
45             e.printStackTrace();
46         }
47         service.shutdown();//关闭线程池
48     }
49 }

如下是执行结果:

 1 线程pool-1-thread-1 正准备接收命令
 2 线程pool-1-thread-2 正准备接收命令
 3 线程pool-1-thread-3 正准备接收命令
 4 线程main 即将发布命令
 5 线程main 已发送命令,正在等待结果
 6 线程pool-1-thread-1 已接收命令
 7 线程pool-1-thread-2 已接收命令
 8 线程pool-1-thread-3 已接收命令
 9 线程pool-1-thread-2 回应命令处理结果
10 线程pool-1-thread-3 回应命令处理结果
11 线程pool-1-thread-1 回应命令处理结果
12 线程main 已收到所有相应结果

Exchanger类可以实现两个线程之间的数据交换:

 1 public class ExchangerTest
 2 {
 3     public static void main(String[] args)
 4     {
 5         //创建一个带有缓存的线程池
 6         ExecutorService service = Executors.newCachedThreadPool();
 7         final Exchanger<String> changer = new Exchanger<String>();
 8         //开启第一个任务
 9         service.execute(new Runnable()
10         {
11             @Override
12             public void run()
13             {
14                 try
15                 {
16                     String dtail1 = "zhangsan";//准备要交换出去的数据
17                     System.out.println("线程 "+Thread.currentThread().getName()+" 正要把"+dtail1+"换出去");
18                     Thread.sleep(new Random().nextInt(1000));
19                     String dtail2 = changer.exchange(dtail1);//换回来的数据
20                     System.out.println("线程 "+Thread.currentThread().getName()+"换回的数据为"+dtail2);
21                 } catch (InterruptedException e)
22                 {
23                     e.printStackTrace();
24                 }
25             }
26         });
27
28         //开启第二个任务
29         service.execute(new Runnable()
30         {
31             @Override
32             public void run()
33             {
34                 try
35                 {
36                     String dtail1 = "lisi";//准备要交换出去的数据
37                     System.out.println("线程 "+Thread.currentThread().getName()+" 正要把"+dtail1+"换出去");
38                     Thread.sleep(new Random().nextInt(1000));
39                     String dtail2 = changer.exchange(dtail1);//换回来的数据
40                     System.out.println("线程 "+Thread.currentThread().getName()+"换回的数据为"+dtail2);
41                 } catch (InterruptedException e)
42                 {
43                     e.printStackTrace();
44                 }
45             }
46         });
47         service.shutdown();
48     }
49 }

如下是执行结果:

1 线程 pool-1-thread-1 正要把zhangsan换出去
2 线程 pool-1-thread-2 正要把lisi换出去
3 线程 pool-1-thread-1换回的数据为lisi
4 线程 pool-1-thread-2换回的数据为zhangsan

以上都是java 5中的一些知识点,大家可以根据实际工作中的需要进行选择使用!!

时间: 2024-08-26 05:39:35

java 5线程中 Semaphore信号灯,CyclicBarrier类,CountDownLatch计数器以及Exchanger类使用的相关文章

Java子线程中的异常处理(通用)

在普通的单线程程序中,捕获异常只需要通过try ... catch ... finally ...代码块就可以了.那么,在并发情况下,比如在父线程中启动了子线程,如何在父线程中捕获来自子线程的异常,从而进行相应的处理呢? 常见错误 也许有人会觉得,很简单嘛,直接在父线程启动子线程的地方try ... catch一把就可以了,其实这是不对的. 原因分析 让我们回忆一下Runnable接口的run方法的完整签名,因为没有标识throws语句,所以方法是不会抛出checked异常的.至于Runtime

Java子线程中操作主线程Private级别数据

两个类分别如下: <pre name="code" class="java">package Demo2; import java.util.*; class Demo2 { private static ArrayList<String> a = new ArrayList<String>(); public static void main(String[] args) { a.add("String0")

【Java】线程中的wait和notify

线程中的同步问题通常使用的是synchronized块,结合wait和notify方法,今天简单做了一个测试.发现当一个线程锁定了某个临界资源后另一个线程会自动等待,以往自己还认为需要自己写代码让其等待呢... 共享资源: package sm.model; import org.apache.log4j.Logger; public class ThreadFuncs { /**  * Logger for this class  */ private static final Logger 

JAVA多线程提高十:同步工具CyclicBarrier与CountDownLatch

今天继续学习其它的同步工具:CyclicBarrier与CountDownLatch 一.CyclicBarrier CyclicBarrier是一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point).在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用.因为该 barrier 在释放等待线程后可以重用,所以称它为循环 的 barrier. CyclicBarrier类似于CountDownL

Java并发包中Semaphore的工作原理、源码分析及使用示例

1. 信号量Semaphore的介绍 我们以一个停车场运作为例来说明信号量的作用.假设停车场只有三个车位,一开始三个车位都是空的.这时如果同时来了三辆车,看门人允许其中它们进入进入,然后放下车拦.以后来的车必须在入口等待,直到停车场中有车辆离开.这时,如果有一辆车离开停车场,看门人得知后,打开车拦,放入一辆,如果又离开一辆,则又可以放入一辆,如此往复. 在这个停车场系统中,车位是公共资源,每辆车好比一个线程,看门人起的就是信号量的作用.信号量是一个非负整数,表示了当前公共资源的可用数目(在上面的

java web项目中后台控制层对参数进行自定义验证 类 Pattern

Pattern pattern = Pattern.compile("/^([1-9]\\d+元*|[0]{0,1})$/");//将给定的正则表达式编译到模式中 if(!"".equals(mmshop.getOriginalPrice().trim())){ if(!pattern.matcher(mmshop.getOriginalPrice().trim()).matches()){ map.put("msg","请输入数字或x

java并发之CountDownLatch、Semaphore和CyclicBarrier

JAVA并发包中有三个类用于同步一批线程的行为,分别是CountDownLatch.Semaphore和CyclicBarrier. CountDownLatch CountDownLatch是一个计数器闭锁,主要的功能就是通过await()方法来阻塞住当前线程,然后等待计数器减少到0了,再唤起这些线程继续执行. 这个类里主要有两个方法,一个是向下减计数器的方法:countdown(),其实现的核心代码如下: public boolean tryReleaseShared(int release

转发---[沧海拾遗]java并发之CountDownLatch、Semaphore和CyclicBarrier

JAVA并发包中有三个类用于同步一批线程的行为,分别是CountDownLatch.Semaphore和CyclicBarrier. CountDownLatch CountDownLatch是一个计数器闭锁,主要的功能就是通过await()方法来阻塞住当前线程,然后等待计数器减少到0了,再唤起这些线程继续执行. 这个类里主要有两个方法,一个是向下减计数器的方法:countdown(),其实现的核心代码如下: public boolean tryReleaseShared(int release

深入理解Java之线程池

原作者:海子 出处:http://www.cnblogs.com/dolphin0520/ 本文归作者海子和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利. 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间. 那么有没有一种办法使得线程可