Java线程池

JAVA多线程的实现方式Java程序中 , 常见有4种方式实现多线程
①继承Thread类
②实现Runnable接口
③实现Callable接口
④使用Executor框架
在JDK5之前 , 创建线程有2种方式 , 一种是继承Thread类 , 另外一种是实现Runnable接口 。这2种方式在执行完任务之后都无法获取执行结果 , 如果需要获取执行结果 , 就必须通过共享变量或者使用线程通信的方式来达到效果 , 这样使用起来就比较麻烦 。自Java 5起 , 就提供了Callable和Future , 通过它们可以在任务执行完毕之后得到任务执行结果 。
方式①举例:继承Thread类 , 实现run()方法 , 调用start()方法启动线程
public class ThreadSample extends Thread { @Override public void run() {System.out.println(this.getName() + " do some work..."); } public static void main(String[] args) {ThreadSample threadSample = new ThreadSample();threadSample.setName("thread-a");threadSample.start(); }}start()方法调用后并不是立即执行多线程代码 , 而是使得该线程变为Ready状态 , 等待CPU分配执行时间 。方式②举例:实现Runnable接口 , 实现run()方法 , 将实例对象传入Thread构造方法
public class ThreadSample implements Runnable { @Override public void run() {System.out.println(Thread.currentThread().getName() + " do some work..."); } public static void main(String[] args) {Thread threadSample = new Thread(new ThreadSample(), "thread-b");threadSample.start(); }}方式③举例:实现Callable接口和FutureTask对象组合
public class ThreadSample implements Callable<Integer> { @Override public Integer call() {int result = 0;for (int i = 0; i <= 10; i++) {result++;}return result; } public static void main(String[] args) throws InterruptedException, ExecutionException {//1、实例化Callable对象ThreadSample callableSample = new ThreadSample();//2、创建装载线程的FutureTask对象FutureTask<Integer> ft = new FutureTask<Integer>(callableSample);//3、启动线程Thread thread = new Thread(ft, "thread-callable");thread.start();//4、获取返回结果Integer result = ft.get();System.out.println("result = " + result); }}与使用Runnable相比 , Callable功能更强大

  • 可以有返回值 , 支持泛型的返回值 , 借助FutureTask类获取返回值;
  • 可以捕获程序执行过程中的异常 。
方式④举例:线程池实现
public class ThreadSample implements Callable<Integer> { @Override public Integer call() {int result = 0;for (int i = 0; i <= 10; i++) {result++;}return result; } public static void main(String[] args) throws InterruptedException, ExecutionException {ExecutorService services = Executors.newSingleThreadExecutor();Future<Integer> future = services.submit(new ThreadSample());System.out.println("result = " + future.get());services.shutdown(); }}以上继承Thread类、实现Runnable接口、实现Callable接口三种方式中 , 理论上优先选用Runnable接口和Callable接口 , 如果有需要返回值则选用Callable接口实现方式 。此外 , 无论何时 , 当看到这种形式的代码:
new Thread(runnable).start()
并且最终希望有一个更加灵活的执行策略时 , 都可以认真考虑使用Executor代替Thread 。
使用线程池的好处在线程池中执行任务线程 , 比起每个任务创建一个线程 , 有很多优势 。
  • 减少系统开销 。重用存在的线程 , 而不是创建新的线程 , 这可以在处理多请求时抵消线程创建、销毁产生的开销 。
  • 提升请求响应性 。在请求到达时 , 工作者线程已经存在 , 可以立即执行 , 因此提高了响应性 。
  • 增强线程的可管理性 。通过调整线程池的大小 , 可以充分利用CPU资源 , 同时可以防止过多的线程相互竞争资源 , 导致应用程序耗尽内存或者失败 。线程池可以对线程资源进行统一分配、调优和监控 。
线程池的工作流程Java线程池的核心实现类是ThreadPoolExecutor类 , 任务提交到线程池时 , 具体处理由ThreadPoolExecutor类的execute()方法执行 。当一个新任务提交到线程池时 , 线程池的处理流程如下:
①判断核心线程池里的线程是否都在执行任务 , 如果不是 , 创建一个新的工作线程来执行任务 。如果是 , 则进行下一步流程 。


推荐阅读