Java并发编程:同步工具类
1.Semaphore类 一个计数信号量,通常用于限制可以访问某些资源(物理或逻辑的)的线程数目。功能和锁有点类似,它一般用于控制对某组资源的访问权限。
acquire()用来获取一个许可,若无许可能够获得,则会一直等待,直到获得许可。
release()用来释放许可。注意,在释放许可之前,必须先获获得许可。
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 e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("线程 " + Thread.currentThread().getName() + " 进入,当前已有 " + (3 - sp.availablePermits()) + "个线程并发"); try { Thread.sleep((long) Math.random() * 1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("线程 " + Thread.currentThread().getName() + "即将离开"); sp.release(); System.out.println("线程 " + Thread.currentThread().getName() + " 已离开,当前已有" + (3 - sp.availablePermits()) + "个线程并发"); } }; service.execute(runnable); } } }
2.CyclicBarrier类一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点。
一组线程等待至某个状态之后再全部同时执行,例如班级出外郊游,当所有人到齐后才出发到下一个目的地。
/* 集齐够了所有线程再进行下一步工作 */ 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(); } }
3.CountDownLatch类一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
CountDownLatch 使用一个计数器来实现,它初始化为一个正,用来表示需要等待的活动事件数。countDown 方法使计数器减一,表示一个事件已经发生了,而await方法等待计数器达到零,此时表示所有需要等待的事件都已发生,只有当计数器到达零时,锁才会开起。如果计数器的初始值不为零,await会一直阻塞直到计数器为零,或者是等待线程中断或超时。
import java.util.concurrent.CountDownLatch; 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); // 裁判吹一声口哨 // 将计数1初始化做一个开/关锁存器,调用countDown()的线程打开 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(); } }
4.Exchanger类 两个线程可以交换对象的同步点。每个线程都在进入 exchange 方法时给出某个对象,相互接受对方准备的对象。
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 { Thread.sleep((long) (Math.random() * 10000)); String data1 = "Drug"; System.out.println("线程" + Thread.currentThread().getName() + "正在把 " + data1 + " 换出去"); String data2 = (String) exchanger.exchange(data1); System.out.println("线程" + Thread.currentThread().getName() + "换回的东西为 " + data2); } catch (Exception e) { e.printStackTrace(); } } }); service.execute(new Runnable() { public void run() { try { Thread.sleep((long) (Math.random() * 10000)); String data1 = "Money"; System.out.println("线程" + Thread.currentThread().getName() + "正在把 " + data1 + " 换出去"); String data2 = (String) exchanger.exchange(data1); System.out.println("线程" + Thread.currentThread().getName() + "换回的东西为" + data2); } catch (Exception e) { e.printStackTrace(); } } }); } }