一、线程同步工具 Semaphore
1、Semaphore 可以维护当前访问自身的线程个数,并提供了同步机制。使用 Semaphore 可以控制同时访问资源的线程个数。相当于蹲坑,一共有3个坑,10个人来,只能三个三个上,三个并发。例如,实现一个文件允许的并发访问数。
2、单个Semaphore,可以实现线程互斥锁的功能。并且可以由一个线程得到‘锁’,再由另一个线程释放‘锁’。这可应用于死锁回复的一些场合。如一个人上厕所,晕在里面了,本来只有里面那个人才能释放。现在可以由其他人释放。
3、Semaphore的具体使用:信号灯。
1)创建:permits-灯(Semaphore)的个数;fair,实现线程进入优先级。true的时候,先到先进
final Semaphore sp = new Semaphore(int permits, boolean fair) ;
2) Semaphore的获取与释放:
Semaphore.acquire();//获取信号灯 Semaphore.release();//释放获取的灯 Semaphore.availablePermits() //被拿走的灯的个数
4、实例:
package com.newThread; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; /** * @title 线程同步工具1:Semaphore实现信号灯 * @description 相当于蹲坑,一共有3个坑,10个人来,只能三个三个上,三个并发。 * 1-Semaphore 可以维护当前访问自身的线程个数,并提供了同步机制。使用Semaphore可以控制同时访问 * 资源的线程个数。例如,实现一个文件允许的并发访问数。 * 2-单个Semaphore,可以实现线程互斥锁的功能。并且可以由一个线程得到‘锁’,再由另一个线程释放‘锁’ * 这可应用于死锁回复的一些场合。如一个人上厕所,晕在里面了,本来只有里面那个人才能释放。现在可以由其他人释放。 * @author SAM-SHO * @Date 2014-8-30 */ public class SemaphoreTest { public static void main(String[] args) { //创建线程池,newCachedThreadPool,有多少任务,开多少线程。但是这边会考虑灯的情况 ExecutorService service = Executors.newCachedThreadPool(); //建立信号灯,有参数fair,实现线程进入优先级。true的时候,先到先进 final Semaphore sp = new Semaphore(3);//只有三个灯 //创建10个线程 for(int i=0;i<10;i++){ Runnable runnable = new Runnable(){ public void run(){ try { sp.acquire();//获取信号灯 } catch (InterruptedException e1) { e1.printStackTrace(); } //sp.availablePermits() 被拿走的灯的个数 System.out.println("线程" + Thread.currentThread().getName() + "进入,当前已有" + (3-sp.availablePermits()) + "线程"); try { Thread.sleep((long)(Math.random()*10000)); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程" + Thread.currentThread().getName() + "即将离开"); sp.release();//释放获取的灯 //下面代码有时候执行不准确 System.out.println("线程" + Thread.currentThread().getName() + "已离开,当前已有" + (3-sp.availablePermits()) + "线程"); } }; service.execute(runnable);//执行10个线程 } } }
二、线程同步工具 CyclicBarrier
1、CyclicBarrier :实现循环使用的路障。
2、表示大家彼此等待,大家集合好后才开始出发,分散活动后又在指定地点集合碰面。如好比整个公司的人员利用周末集体郊游,先各自从家出发到公司集合后,再同时出发到公园游玩。先到的阻塞,不行动。在指定地点集合后再同时开始就餐...
3、CyclicBarrier 的使用
CyclicBarrier.getNumberWaiting() //正在等待的线程个数,三个就能走,从 0 开始数数 CyclicBarrier.await();//只有三个都到了才会运行下去,即集合地点
4、实例代码:
package com.newThread; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * * CyclicBarrierTest.java * * @title 线程同步工具2:路障,实现循环使用的路障 * @description CyclicBarrier :表示大家彼此等待,大家集合好后才开始出发,分散活动后又在指定地点集合碰面 * 1-好比整个公司的人员利用周末集体郊游,先各自从家出发到公司集合后,再同时出发到公园游玩。先到的阻塞,不行动。 * 在指定地点集合后再同时开始就餐... * @author SAM-SHO * @Date 2014-8-31 */ public class CyclicBarrierTest { public static void main(String[] args) { //创建线程池 ExecutorService service = Executors.newCachedThreadPool(); //创建三个路障,即一定要三个一起行动 final CyclicBarrier cb = new CyclicBarrier(3); //3个线程 for(int i=0;i<3;i++){ Runnable runnable = new Runnable(){ public void run(){ try { Thread.sleep((long)(Math.random()*10000)); //cb.getNumberWaiting() 正在等待的线程个数,三个就能走, System.out.println("线程" + Thread.currentThread().getName() + "即将到达集合地点1,当前已有" + (cb.getNumberWaiting()+1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候")); cb.await();//只有三个都到了才会运行下去,即集合地点 Thread.sleep((long)(Math.random()*10000)); System.out.println("线程" + Thread.currentThread().getName() + "即将到达集合地点2,当前已有" + (cb.getNumberWaiting()+1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候")); cb.await(); Thread.sleep((long)(Math.random()*10000)); System.out.println("线程" + Thread.currentThread().getName() + "即将到达集合地点3,当前已有" + (cb.getNumberWaiting() + 1) + "个已经到达," + (cb.getNumberWaiting()==2?"都到齐了,继续走啊":"正在等候")); cb.await(); } catch (Exception e) { e.printStackTrace(); } } }; service.execute(runnable);//启动线程池 } service.shutdown();//关闭 } }
三、线程同步工具 CountDownLatch
1、CountdownLatch 倒计时计时器。
2、犹如倒计时的计时器,调用CountdownLatch对象的countDown()方法,就将计时器减一当计时器到达0时,则所有线程或单个线程开始执行。
3、可以实现一个人(多人)等待其他所有人都来通知他,可以实现一个通知多个人的效果。类似裁判一声令下运动员同时开始奔跑。
3、实例:
package com.newThread; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * * CountdownLatchTest.java * * @title 线程同步工具3:CountdownLatch 倒计时 * @description * 1-犹如倒计时的计时器,调用CountdownLatch对象的countDown()方法,就将计时器减一 * 当计时器到达0时,则所有线程或单个线程开始执行 * 2-可以实现一个人(多人)等待其他所有人都来通知他,可以实现一个通知多个人的效果。类似裁判一声令下 * 运动员同时开始奔跑 * @author SAM-SHO * @Date 2014-8-31 */ public class CountdownLatchTest { public static void main(String[] args) { //创建线程池 ExecutorService service = Executors.newCachedThreadPool(); //创建倒计时的计时器,初始值分别为1和3。他们的计时器在别人手中。 //可以一个人有三个人的计时器,也可以三个人有一个人的计时器 //即实现双方的数据交互 final CountDownLatch cdOrder = new CountDownLatch(1);//子线程的计时器 final CountDownLatch cdAnswer = new CountDownLatch(3);//主线程的计时器 //创建3子个线程 for(int i=0;i<3;i++){ Runnable runnable = new Runnable(){//她们的计时器为cdAnswer public void run(){ try { System.out.println("线程" + Thread.currentThread().getName() + "正准备接受命令"); cdOrder.await();//子线程自己等待 System.out.println("线程" + Thread.currentThread().getName() + "已接受命令"); Thread.sleep((long)(Math.random()*10000)); System.out.println("线程" + Thread.currentThread().getName() + "回应命令处理结果"); cdAnswer.countDown();//主线程,计数器减一。只有三个子线程都结束,才会结束主线程的计时器 } catch (Exception e) { e.printStackTrace(); } } }; service.execute(runnable); } try { //主线程:main 她的计时器为cdAnswer Thread.sleep((long)(Math.random()*10000)); System.out.println("线程" + Thread.currentThread().getName() + "即将发布命令"); cdOrder.countDown();//让三个子线程,计时器减一,发布命令 System.out.println("线程" + Thread.currentThread().getName() + "已发送命令,正在等待结果"); cdAnswer.await();//主线程等待 System.out.println("线程" + Thread.currentThread().getName() + "已收到所有响应结果"); } catch (Exception e) { e.printStackTrace(); } service.shutdown(); } }
四、线程同步工具 Exchanger
1、Exchanger:用于实现两个人之间的数据交换。
2、每个人在完成一定的事务后想与对方交换数据,第一个先拿出数据的人将一直等待第二个人拿着数据到来时,才能彼此交换数据。
3、实例:
package com.newThread; import java.util.concurrent.Exchanger; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * * ExchangerTest.java * * @title 线程同步工具4:Exchanger * @description * 1-用于实现两个人之间的数据交换。每个人在完成一定的事务后想与对方交换数据, * 第一个先拿出数据的人将一直等待第二个人拿着数据到来时,才能彼此交换数据 * @author SAM-SHO * @Date 2014-8-31 */ public class ExchangerTest { public static void main(String[] args) { //创建线程池 ExecutorService service = Executors.newCachedThreadPool(); final Exchanger exchanger = new Exchanger(); //启动一个线程 service.execute(new Runnable(){ public void run() { try { String data1 = " 邵小宝 "; 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(){ public void run() { try { String data1 = " 赵小妞 "; 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){ } } }); } }