先来讲解一下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类使用的更多相关文章

  1. Android进阶——多线程系列之Semaphore、CyclicBarrier、CountDownLatch

    今天向大家介绍的是多线程开发中的一些辅助类,他们的作用无非就是帮助我们让多个线程按照我们想要的执行顺序来执行.如果我们按照文字来理解Semaphore.CyclicBarrier.CountDownL ...

  2. java的线程中的Runnable

                      在java中可有两种方式实现多线程,一种是继承Thread类,一种是实现Runnable接口:Thread类是在java.lang包中定义的.一个类只要继承了Thr ...

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

    在普通的单线程程序中,捕获异常只需要通过try ... catch ... finally ...代码块就可以了.那么,在并发情况下,比如在父线程中启动了子线程,如何正确捕获子线程中的异常,从而进行相 ...

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

    两个类分别如下: <pre name="code" class="java">package Demo2; import java.util.*; ...

  5. 转:Java子线程中的异常处理(通用)

    引自:https://www.cnblogs.com/yangfanexp/p/7594557.html 在普通的单线程程序中,捕获异常只需要通过try ... catch ... finally . ...

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

    今天继续学习其它的同步工具:CyclicBarrier与CountDownLatch 一.CyclicBarrier CyclicBarrier是一个同步辅助类,它允许一组线程互相等待,直到到达某个公 ...

  7. JUC-JUC强大的辅助类讲解(Semaphore、CyclicBarrier、CountDownLatch)

    一.CountDownLatch 减少计数 1.原理 * CountDownLatch主要有两个方法,当一个或多个线程调用await方法时,这些线程会阻塞. * 其它线程调用countDown方法会将 ...

  8. JAVA多线程学习十三 - 同步工具CyclicBarrier与CountDownLatch

    一.CyclicBarrier CyclicBarrier是一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point).在涉及一组固定大小的线程的程序 ...

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

    1. 信号量Semaphore的介绍 我们以一个停车场运作为例来说明信号量的作用.假设停车场只有三个车位,一开始三个车位都是空的.这时如果同时来了三辆车,看门人允许其中它们进入进入,然后放下车拦.以后 ...

随机推荐

  1. Linux显示机器的处理器架构

    Linux显示机器的处理器架构 youhaidong@youhaidong-ThinkPad-Edge-E545:~$ arch x86_64 youhaidong@youhaidong-ThinkP ...

  2. Flex和Java通信报错

    1.错误描述 11-30 18:15:52 ERROR [localhost-startStop-1] org.springframework.web.servlet.FrameworkServlet ...

  3. C# 时间格式化大全

    DateTime dt = DateTime.Now; Label1.Text = dt.ToString();//2005-11-5 13:21:25        Label2.Text = dt ...

  4. hihocoder Challenge 29 B.快速乘法

    这题的题解和我写的有一拼,异常简洁,爆炸. 这题思路dp 表示的是讨论到第位,并比原数的前n位多了 显然j只能取0,1,毕竟2进制嘛 之后转移就好了,注意下面两个重要状态 #include <c ...

  5. C#的动态链接库和XML配置

    今天对昨天的实例进行了改进和提高,将堆排序和冒泡排序封装在一个动态链接库中,提供函数调用和事件委托.此外加入XML进行配置,在XML中存入相关配置信息,提供一个单独的XmlClass对其进行操作,加深 ...

  6. 关于js中 toFixed()的一个小坑

    作为一名前端,大家都应该知道,toFixed()的作用,toFixed()经常用于前台与后台数据格式的转换,套用下w3c上面的定义: 定义和用法toFixed(n) 方法可把 Number 四舍五入为 ...

  7. 机器学习-kNN

    基于Peter Harrington所著<Machine Learning in Action> kNN,即k-NearestNeighbor算法,是一种最简单的分类算法,拿这个当机器学习 ...

  8. 【MyBatis源码分析】Configuration加载(下篇)

    元素设置 继续MyBatis的Configuration加载源码分析: private void parseConfiguration(XNode root) { try { Properties s ...

  9. 初探WebSocket

    初探WebSocket node websocket socket.io 我们平常开发的大部分web页面都是主动'拉'的形式,如果需要更新页面内容,则需要"刷新"一个,但Slack ...

  10. rpm 相关问题

    specfies multiple packages 错误 这是安装了多个相同的rpm包,所以无法卸载,可以加上--allmatches rpm -e xxx.rpm --allmatches err ...