国内最全IT社区平台 联系我们 | 收藏本站
华晨云阿里云优惠2
您当前位置:首页 > 互联网 > JDK5新特性之线程同步工具类(三)

JDK5新特性之线程同步工具类(三)

来源:程序员人生   发布时间:2014-11-22 08:46:08 阅读次数:3158次

1. Semaphore

Semaphore可以控制同时访问资源的线程个数, 例如: 实现1个文件允许的并发访问数.

Semaphore实现的功能就类似厕所有5个坑, 加入有10个人要上厕所, 那末同时只能有5个人能够占用, 当5个人中的任何1个人离开后, 其中在等待的另外5个人中就有1个可以占用了. 另外等待的5个人中可以是随机取得优先机会, 也能够使依照先来后到的顺序取得机会, 这取决于构造Semaphore对象时传入的参数选项.

public class SemaphoreTest { public static void main(String[] args) { // 创建1个线程池 ExecutorService service = Executors.newCachedThreadPool(); final Semaphore sp = new Semaphore(3); // 表示当前有3盏灯(允许3个并发) // 启动5个线程 for (int i = 0; i < 5; i++) { service.execute(new Runnable() { public void run() { try { sp.acquire(); // 点亮1盏灯 // availablePermits: 表示可使用的灯 System.out.println("线程" + Thread.currentThread().getName() + " 进入,当前已有" + (3 - sp.availablePermits()) + "个并发"); Thread.sleep((long) (Math.random() * 10000)); System.out.println("线程" + Thread.currentThread().getName() + " 行将离开"); sp.release(); // 熄灭1盏灯(释放) System.out.println("线程" + Thread.currentThread().getName() + " 已离开,当前已有" + (3 - sp.availablePermits()) + "个并发"); } catch (InterruptedException e) { e.printStackTrace(); } } }); } } }
单个Semaphore对象可以实现互斥锁的功能, 并且可以是由1个线程取得了"锁", 再由另外一个线程释放"锁", 这可利用于死锁恢复的1些场合.

线程pool⑴-thread⑴ 进入,当前已有1个并发 线程pool⑴-thread⑵ 进入,当前已有2个并发 线程pool⑴-thread⑷ 进入,当前已有3个并发 线程pool⑴-thread⑷ 行将离开 线程pool⑴-thread⑷ 已离开,当前已有2个并发 线程pool⑴-thread⑶ 进入,当前已有3个并发 线程pool⑴-thread⑵ 行将离开 线程pool⑴-thread⑵ 已离开,当前已有2个并发 线程pool⑴-thread⑸ 进入,当前已有3个并发 线程pool⑴-thread⑸ 行将离开 线程pool⑴-thread⑸ 已离开,当前已有2个并发 线程pool⑴-thread⑴ 行将离开 线程pool⑴-thread⑴ 已离开,当前已有1个并发 线程pool⑴-thread⑶ 行将离开 线程pool⑴-thread⑶ 已离开,当前已有0个并发


2. CyclicBarrier

表示大家彼此等待,集合好后才开始动身,分散活动后又在指定地点集合碰面。

这就好比全部公司的人员里利用周末时间集体远足1样,先各自从家动身到公司集合后,再同时动身到公园游玩,在指定地点集合后再同时开始就餐。

public class CyclicBarrierTest { public static void main(String[] args) { // 开启1个线程池 ExecutorService executorService = Executors.newCachedThreadPool(); // 参数3: 表示有3个到齐了才可以往下走,否则1直处于等待状态 final CyclicBarrier cb = new CyclicBarrier(3); // 创建3个线程 for(int i = 0; i < 3; i++){ executorService.execute(new Runnable(){ @Override public void run(){ try { Thread.sleep((long)(Math.random() * 1000)); // 每一个线程“休息”的时间不同 System.out.println("线程" + Thread.currentThread().getName() + "行将到达集合地点1,当前已有" + (cb.getNumberWaiting() + 1) + "个已到达," + (cb.getNumberWaiting() == 2 ? "都到齐了,继续前进" : "正在等候")); cb.await(); // 先到的等待后到的,当3个都到达时才会继续向下履行 Thread.sleep((long)(Math.random() * 1000)); // 每一个线程“休息”的时间不同 System.out.println("线程" + Thread.currentThread().getName() + "行将到达集合地点2,当前已有" + (cb.getNumberWaiting() + 1) + "个已到达," + (cb.getNumberWaiting() == 2 ? "都到齐了,继续前进" : "正在等候")); cb.await(); Thread.sleep((long)(Math.random()*1000)); // 每一个线程“休息”的时间不同 System.out.println("线程" + Thread.currentThread().getName() + "行将到达集合地点3,当前已有" + (cb.getNumberWaiting() + 1) + "个已到达,"+ (cb.getNumberWaiting() == 2 ? "都到齐了,继续前进" : "正在等候")); cb.await(); } catch (Exception e) { e.printStackTrace(); } } }); } executorService.shutdown(); } }
3个线程干完各自的任务,在不同的时刻到达集合地点后,就能够接着忙各自的工作去了,再到达新的集合点,再去忙各自的工作。

线程pool⑴-thread⑵行将到达集合地点1,当前已有1个已到达,正在等候 线程pool⑴-thread⑶行将到达集合地点1,当前已有2个已到达,正在等候 线程pool⑴-thread⑴行将到达集合地点1,当前已有3个已到达,都到齐了,继续前进 线程pool⑴-thread⑵行将到达集合地点2,当前已有1个已到达,正在等候 线程pool⑴-thread⑶行将到达集合地点2,当前已有2个已到达,正在等候 线程pool⑴-thread⑴行将到达集合地点2,当前已有3个已到达,都到齐了,继续前进 线程pool⑴-thread⑶行将到达集合地点3,当前已有1个已到达,正在等候 线程pool⑴-thread⑵行将到达集合地点3,当前已有2个已到达,正在等候 线程pool⑴-thread⑴行将到达集合地点3,当前已有3个已到达,都到齐了,继续前进

3. CountDownLatch

犹如倒计时计数器, 调用CountDownLatch对象的countDown方法就将计数器减1, 当计数到达0时, 则所有等待者或单个等待者开始履行.

利用: 裁判1声口令, 运动员同时开始奔跑, 当所有运动员都跑到终点后裁判公布结果. 还可以实现1个计划需要多个领导都签字后才能继续向下实行的情况.

public class CountDownLatchTest { public static void main(String[] args) throws Exception { ExecutorService service = Executors.newCachedThreadPool(); // 子计数器, count为1 final CountDownLatch subCounter = new CountDownLatch(1); // 主计数器, count为3 final CountDownLatch mainCounter = new CountDownLatch(3); for(int i = 0; i < 3; i++){ service.execute(new Runnable() { @Override public void run() { try { System.out.println("线程 "+ Thread.currentThread().getName()+"正准备接受命令!"); subCounter.await(); // 子线程等待 System.out.println("线程 "+ Thread.currentThread().getName()+"已接受命令!"); Thread.sleep((long)Math.random() * 10000); System.out.println("线程 "+ Thread.currentThread().getName()+"回应命令处理结果!"); mainCounter.countDown(); // 将计数器身上的计数减1, 当计数为0时, 主线程将开始履行 } catch (Exception e) { e.printStackTrace(); } } } ); } Thread.sleep((long)Math.random() * 1000); System.out.println("线程 "+ Thread.currentThread().getName()+"行将发布命令!"); subCounter.countDown(); // 将计数器身上的计数减1, 当计数为0时, 子线程开始履行 System.out.println("线程 "+ Thread.currentThread().getName()+"已发送命令,正在等待结果!"); mainCounter.await(); // 主线程等待 System.out.println("线程 "+ Thread.currentThread().getName()+"已收到所有响应结果!"); service.shutdown(); } }
线程 pool⑴-thread⑴正准备接受命令! 线程 pool⑴-thread⑶正准备接受命令! 线程 pool⑴-thread⑵正准备接受命令! 线程 main行将发布命令! 线程 main已发送命令,正在等待结果! 线程 pool⑴-thread⑵已接受命令! 线程 pool⑴-thread⑶已接受命令! 线程 pool⑴-thread⑴已接受命令! 线程 pool⑴-thread⑶回应命令处理结果! 线程 pool⑴-thread⑵回应命令处理结果! 线程 pool⑴-thread⑴回应命令处理结果! 线程 main已收到所有响应结果!

4. Exchanger

用于实现两个人之间的数据交换, 每一个人在完成1定的事务后想与对方交换数据, 第1个先拿出数据的人将1直等待第2个人拿着数据到来时, 才能彼此交换数据:

public class ExchangerTest { public static void main(String[] args) { ExecutorService service = Executors.newCachedThreadPool(); final Exchanger exchanger = new Exchanger(); service.execute(new Runnable() { @Override public void run() { try { String data1 = "aaa"; System.out.println("线程 " + Thread.currentThread().getName() + " 正在把数据: " + data1 + " 换出去!"); Thread.sleep((long) Math.random() * 10000); String data2 = (String) exchanger.exchange(data1); System.out.println("线程 " + Thread.currentThread().getName() + " 换回的数据为:" + data2); } catch (Exception e) { } } }); service.execute(new Runnable() { @Override public void run() { try { String data1 = "bbb"; System.out.println("线程 " + Thread.currentThread().getName() + " 正在把数据: " + data1 + " 换出去!"); Thread.sleep((long) Math.random() * 10000); String data2 = (String) exchanger.exchange(data1); System.out.println("线程 " + Thread.currentThread().getName() + " 换回的数据为:" + data2); } catch (Exception e) { } } }); } }
线程 pool⑴-thread⑴ 正在把数据: aaa 换出去! 线程 pool⑴-thread⑵ 正在把数据: bbb 换出去! 线程 pool⑴-thread⑴ 换回的数据为:bbb 线程 pool⑴-thread⑵ 换回的数据为:aaa




生活不易,码农辛苦
如果您觉得本网站对您的学习有所帮助,可以手机扫描二维码进行捐赠
程序员人生
------分隔线----------------------------
分享到:
------分隔线----------------------------
关闭
程序员人生