并发包下一些并发类
引言:JDK1.5的并发包不仅仅提供了前文所说的线程池框架,还提供了一系列并发类,来便于我们编写高并发代码,本文我们来一一介绍。
一、CountDownLatch类
代码如下:
package com.example.first; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class UseCountDown { public static void main(String args[]) throws InterruptedException { CountDownLatch countDownLatch = new CountDownLatch(2); Runnable runnable1 = new Runnable() { @Override public void run() { System.out.println("线程1来了,await阻塞"); try { countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("阻塞结束,开始执行"); } }; Runnable runnable2 = new Runnable() { @Override public void run() { System.out.println("线程2来了"); countDownLatch.countDown(); } }; Runnable runnable3 = new Runnable() { @Override public void run() { System.out.println("线程3来了"); countDownLatch.countDown(); } }; ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5); fixedThreadPool.execute(runnable1); fixedThreadPool.execute(runnable2); fixedThreadPool.execute(runnable3); fixedThreadPool.shutdown(); } }
功能主要是提供了两个方法,一个是await(),用于阻塞当前线程,一个是countDown方法,用于改变CountDownLatch对象的状态。
在CountDownLatch对象初始化的时候,需要在构造函数下加上一个整形的变量i,而await方法就会阻塞线程,只有当其他线程,执行了i次countDown方法,才能将被await阻塞的方法给重新激活。
使用方式是十分的简单,使用场景主要在监听其他线程的初始化操作,当初始化完毕之后,便会提醒主线程开始运行。
二、CyclicBarrier类
代码如下:
package com.example.first; import java.util.concurrent.CountDownLatch; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class UseBarrier { public static void main(String args[]) throws InterruptedException { // CountDownLatch countDownLatch = new CountDownLatch(2); CyclicBarrier cyclicBarrier = new CyclicBarrier(4); Runnable runnable1 = new Runnable() { @Override public void run() { System.out.println("线程1准备好了"); try { cyclicBarrier.await(); } catch (Exception e) { e.printStackTrace(); } System.out.println("阻塞结束,线程1开始执行"); } }; Runnable runnable2 = new Runnable() { @Override public void run() { System.out.println("线程2准备好了"); try { cyclicBarrier.await(); } catch (Exception e) { e.printStackTrace(); } System.out.println("阻塞结束,线程2开始执行"); } }; Runnable runnable3 = new Runnable() { @Override public void run() { System.out.println("线程3准备好了"); try { cyclicBarrier.await(); } catch (Exception e) { e.printStackTrace(); } System.out.println("阻塞结束,线程3开始执行"); } }; ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5); fixedThreadPool.execute(runnable1); fixedThreadPool.execute(runnable2); fixedThreadPool.execute(runnable3); fixedThreadPool.shutdown(); } }
特地去查了一下Barrier是什么意思,大概意思就是栅栏的意思,十分形象。实例化的方式和CountDown很像,都是有一个整数为参数的构造函数,也提供了await方法用于阻塞当前线程,激活线程的时机是当await的数量到达了构造参数中整数的值时。
十分贴切他的意思--栅栏,只有当线程都到齐了,才能各就各位起跑。
三、Future和FutureTask类
代码如下:
package com.example; import java.util.concurrent.*; public class UseFuture { public static void main(String args[]) throws Exception { Callable<String> callable = new Callable<String>() { @Override public String call() throws Exception { Thread.sleep(3000); return "future开始!"; } }; FutureTask<String> futureTask = new FutureTask<String>(callable); ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5); fixedThreadPool.submit(futureTask); System.out.println(futureTask.get()); fixedThreadPool.shutdown(); } }
实现方式,在很早之前写过,但是忘了大概。核心就是要使用Callable接口,重写里面的call方法,call方法有返回值,返回类型为Callable的泛型对象,将Callable出来的对象传入FutureTask的构造方法,再将FutureTask对象传给线程池的submit方法。
submit和execute在大多数情况下无异,但是submit能够传入callable参数,返回Future参数,值得一说的是,FutureTask实现了Callable接口和Future。最后,当主线程调用了FutureTask的get()方法,便会等待FutureTask任务线程执行,返回call方法的值。这是JDK对Future模式的一种实现。