多线程系列三(同步工具类)
今天博客我总结了一下多线程中关于四个同步工具类的使用,每个同步工具类都有自己应用的场景,例如:
信号灯(Semaphore):
应用场景:办公室里有一台打印机,只能让一个人来打印东西,如果别人来了就会被阻塞住,这个人打印完了才会让下一个人来继续打印,如果办公室里面多买了两台打印机,一共有三台打印机了,这样办公室里面就可以同时来三个人打印,再有多余的人才会被阻塞住,主要其中一台打印机空闲下来就会允许后面的人继续来打印。
示例代码:
package com.dmsd.thread;
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore;
public class SemaphoreTest { public static void main(String[] args) { ExecutorService service = Executors.newCachedThreadPool();//定义一个线程池 final Semaphore sp = new Semaphore(3); for(int i=0;i<10;i++){ Runnable runnable = new Runnable(){ public void run(){ try { sp.acquire(); } catch (InterruptedException e1) { e1.printStackTrace(); } 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); } }
} |
运行结果:
线程pool-1-thread-3进入,当前已有2个并发 线程pool-1-thread-4进入,当前已有3个并发 线程pool-1-thread-1进入,当前已有2个并发 线程pool-1-thread-4即将离开 线程pool-1-thread-4已离开,当前已有2个并发 线程pool-1-thread-5进入,当前已有3个并发 线程pool-1-thread-3即将离开 线程pool-1-thread-3已离开,当前已有2个并发 线程pool-1-thread-2进入,当前已有3个并发
|
Semaphore可以维护当前访问自身的线程个数,并提供了同步机制,使用Semaphore可以控制同时访问资源的线程个数。
同步计数器(CountDownLatch):
应用场景:运动场上,裁判一下口令,所有运动员开始奔跑,每个运动员跑到终点都会给裁判返回一个结果,只要所有的运动员都到场终点以后裁判才会公布比赛结果。
示例代码:
package com.dmsd.thread; import java.util.concurrent.CountDownLatch; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;
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(){ 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 { 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();
} } |
运行结果:
Thread-0 be ready to read data! Thread-0have read data :null Thread-1 be ready to write data! Thread-1 have write data: 4394 Thread-3 be ready to write data! Thread-3 have write data: 6867 Thread-4 be ready to read data! Thread-2 be ready to read data! Thread-4have read data :6867 Thread-2have read data :6867 Thread-5 be ready to write data! Thread-5 have write data: 7615 Thread-0 be ready to read data! Thread-0have read data :7615 Thread-1 be ready to write data! Thread-1 have write data: 6050 Thread-3 be ready to write data! Thread-3 have write data: 3908 Thread-4 be ready to read data! Thread-2 be ready to read data!
|
该同步工具可以根据多个计数器组合,既可以控制线程的开始,也可以控制现场的结束。
障碍器(CyclicBarrier):
应用场景:一个旅游团到达旅游地之后,导游说每个人可以自由参观,等到下午三点的时候大家聚集到一起然后一起返回。
示例代码:
package com.dmsd.thread; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;
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(){ public void run(){ try { Thread.sleep((long)(Math.random()*10000)); 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(); } } |
线程间数据交换(Exchanger)
应用场景:
敌对的双方互相交换人质,只有双方都准备好之后同时进行交换。
示例代码:
package com.dmsd.thread; import java.util.concurrent.Exchanger; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;
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 = "zxx"; 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 = "lhm"; 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-1-thread-1正在把数据zxx换出去 线程pool-1-thread-2正在把数据lhm换出去 线程pool-1-thread-1换回的数据为lhm 线程pool-1-thread-2换回的数据为zxx |
四种同步工具各有各的应用场景,根据自己的具体需求,我们可以综合使用这几种同步工具来更好的实现我们的业务。