先来讲解一下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中的一些知识点,大家可以根据实际工作中的需要进行选择使用!!

最新文章

  1. MVVM与Backbone demo
  2. 第一课1、ROS
  3. Atitit 函数式编程与命令式编程的区别attilax总结 &#160;qbf
  4. hadoop fs -mkdir testdata错误 提示No such file or directory
  5. 如何在nopcommerce3.3注册页面添加密码强度检查仪?
  6. MySQL5.5半同步模式
  7. 码表由来:ascll码-Gbk2312-GBK-Unicode-UTF-8
  8. Codeforces Round #337 (Div. 2) D. Vika and Segments 线段树扫描线
  9. HTML5 LocalStorage 本地存储总结
  10. 原生JS实现淘宝无缝轮播
  11. 使用 webpack 打包 font 字体的问题
  12. Windows 2012安装odoo12
  13. loadrunner&#160;场景设计-制定负载测试计划
  14. js 时间戳和日期互转
  15. JS+Ajax+Servlet:记录页面访问时间
  16. flask配置日志输出文件
  17. python基础学习十 logging模块详细使用【转载】
  18. Vue生命周期函数
  19. elasticsearch从入门到出门-05-集群之踩坑
  20. C# 利用Aspose.Cells .dll将本地excel文档转化成pdf(完美破解版 无水印 无中文乱码)

热门文章

  1. pat1021-1030
  2. hihocoder1391 Country
  3. 洛谷2709 小B的询问(莫队)
  4. [BZOJ2752][HAOI2012]高速公路
  5. Java中关于nextInt()、next()和nextLine()的理解
  6. JWT 在前后端分离中的应用与实践
  7. C++学习-11
  8. Thinking in Java 第二章学习笔记
  9. EasyNetQ WithTopic过滤失效的解决方案
  10. js备战春招の三