转:http://coolxing.iteye.com/blog/1236588
服务器应用程序经常需要处理执行时间很短而数目巨大的请求, 如果为每一个请求创建一个新的线程, 会导致一些问题的出现, 如:
1. 性能瓶颈. 线程的创建和销毁需要执行大量的后台操作, 如果单个请求的执行时间很短, 有可能花在创建和销毁线程上的时间大于真正执行请求的时间.
2. 可能会导致资源不足. 大量的并发请求意味着需要创建大量的线程, 过多的线程存在会吞噬大量的系统资源, 而且CPU需要在这些线程间不断切换, 这可能引发"切换过度"的问题.
为了适应上述场合, java在JDK1.5中引入了线程池的概念. 线程池中存放着一定数量的已创建好的线程, 当一个请求到来时, 只需从线程池中取出一个线程来执行请求, 请求完成后再将线程归还给线程池. 同时, 我们可以为线程池指定最大的线程数量, 当池中所有线程都处于活动状态下, 新的任务会排队等候, 直到之前的某个任务处理完成后, 新的任务才能得到处理.
创建线程池. java.util.concurrent.Executors类提供了多个静态方法用于创建线程池.
|--public static ExecutorService newFixedThreadPool(int nThreads): 创建一个可重用的固定线程数的线程池. 如果池中所有的nThreads个线程都处于活动状态时提交任务(任务通常是Runnable或Callable对象), 任务将在队列中等待, 直到池中出现可用线程.
|--public static ExecutorService newCachedThreadPool(): 调用此方法创建的线程池可根据需要自动调整池中线程的数量. 执行任务时将重用存在先前创建的线程(如果池中存在可用线程的话). 如果池中没有可用线程, 将创建一个新的线程, 并将其添加到池中. 池中的线程超过60秒未被使用就会被销毁, 因此长时间保持空闲的CachedThreadPool不会消耗额外的资源.
|--public static ExecutorService newSingleThreadExecutor(): 创建一个单线程的Executor. 这个Executor保证按照任务提交的顺序依次执行任务.
|--public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize): 创建一个可重用的固定线程数的线程池. ScheduledExecutorService是ExecutorService的子接口, 调用ScheduledExecutorService的相关方法, 可以延迟或定期执行任务.
以上静态方法均使用默认的ThreadFactory(即
Executors.defaultThreadFactory()方法的返回值)创建线程, 如果想要指定ThreadFactory, 可调用他们的重载方法.通过指定ThreadFactory, 可以定制新建线程的名称, 线程组, 优先级, 守护线程状态等.
如果Executors提供的创建线程池的方法无法满足要求, 可以使用ThreadPoolExecutor类创建线程池.
提交任务. 所有的线程池都是ExecutorService及其子类的对象, 因此, 可以调用ExecutorService的相关方法提交任务.
|--void execute(Runnable command): 使用池中已存在的线程或新建一个线程执行command.
- public class ExecutorsDemo {
- public static void main(String[] args) throws Exception {
- System.out.println("----------------FixedThreadPool---------------------");
- ExecutorService fixedPool = getFixedThreadPool();
- executeThread(fixedPool);
- // 为了避免混淆, 需要等待executeThread(fixedPool)执行完成
- Thread.sleep(3000);
- System.out.println("----------------CashedThreadPool---------------------");
- ExecutorService cashedPool = getCashedThreadPool();
- executeThread(cashedPool);
- // 为了避免混淆, 需要等待executeThread(cashedPool)执行完成
- Thread.sleep(3000);
- System.out.println("----------------SingleThreadExecutor---------------------");
- ExecutorService singleExecutor = getSingleThreadExecutor();
- executeThread(singleExecutor);
- }
- // 只存在一个线程的线程池
- private static ExecutorService getSingleThreadExecutor() {
- return Executors.newSingleThreadExecutor();
- }
- // 创建一个根据需要自动调整大小的线程池
- private static ExecutorService getCashedThreadPool() {
- return Executors.newCachedThreadPool();
- }
- // 创建一个可重用的固定线程数的线程池
- private static ExecutorService getFixedThreadPool() {
- return Executors.newFixedThreadPool(2);
- }
- private static void executeThread(ExecutorService pool) {
- Thread t1 = new MyThread();
- Thread t2 = new MyThread();
- Thread t3 = new MyThread();
- Thread t4 = new MyThread();
- // 将Tread放入线程池中执行
- // MyThread类继承自Thread, 而Thread类实现了Runnable接口
- pool.execute(t1);
- pool.execute(t2);
- pool.execute(t3);
- pool.execute(t4);
- // 关闭线程池
- pool.shutdown();
- }
- private static final class MyThread extends Thread {
- @Override
- public void run() {
- super.run();
- System.out.println(Thread.currentThread().getName() + ": is running!");
- }
- }
- }
public class ExecutorsDemo { public static void main(String[] args) throws Exception { System.out.println("----------------FixedThreadPool---------------------"); ExecutorService fixedPool = getFixedThreadPool(); executeThread(fixedPool); // 为了避免混淆, 需要等待executeThread(fixedPool)执行完成 Thread.sleep(3000); System.out.println("----------------CashedThreadPool---------------------"); ExecutorService cashedPool = getCashedThreadPool(); executeThread(cashedPool); // 为了避免混淆, 需要等待executeThread(cashedPool)执行完成 Thread.sleep(3000); System.out.println("----------------SingleThreadExecutor---------------------"); ExecutorService singleExecutor = getSingleThreadExecutor(); executeThread(singleExecutor); } // 只存在一个线程的线程池 private static ExecutorService getSingleThreadExecutor() { return Executors.newSingleThreadExecutor(); } // 创建一个根据需要自动调整大小的线程池 private static ExecutorService getCashedThreadPool() { return Executors.newCachedThreadPool(); } // 创建一个可重用的固定线程数的线程池 private static ExecutorService getFixedThreadPool() { return Executors.newFixedThreadPool(2); } private static void executeThread(ExecutorService pool) { Thread t1 = new MyThread(); Thread t2 = new MyThread(); Thread t3 = new MyThread(); Thread t4 = new MyThread(); // 将Tread放入线程池中执行 // MyThread类继承自Thread, 而Thread类实现了Runnable接口 pool.execute(t1); pool.execute(t2); pool.execute(t3); pool.execute(t4); // 关闭线程池 pool.shutdown(); } private static final class MyThread extends Thread { @Override public void run() { super.run(); System.out.println(Thread.currentThread().getName() + ": is running!"); } } }
程序的输出为:
----------------FixedThreadPool---------------------
pool-1-thread-1: is running!
pool-1-thread-2: is running!
pool-1-thread-2: is running!
pool-1-thread-1: is running!
----------------CashedThreadPool---------------------
pool-2-thread-1: is running!
pool-2-thread-2: is running!
pool-2-thread-4: is running!
pool-2-thread-3: is running!
----------------SingleThreadExecutor---------------------
pool-3-thread-1: is running!
pool-3-thread-1: is running!
pool-3-thread-1: is running!
pool-3-thread-1: is running!
|--Future<T> submit(Callable<T> task): 使用池中已存在的线程或新建一个线程执行task, 与execute()方法不同的是, 该方法会返回线程的执行结果. submit方法接受一个Callable<T>对象, Callable<T>接口是一个泛型接口, 实现Callable<T>接口需要重写其中的call()方法, call()方法将返回一个T对象. submit方法的返回值是Future<T>对象, 调用该对象的get()可以获得call()方法的返回值.
- public class FutureDemo {
- public static void main(String[] args) throws Exception {
- ExecutorService pool = Executors.newFixedThreadPool(2);
- Future<Integer> intFuture = pool.submit(new IntegerCallable());
- // get()方法将阻塞主线程, 直到IntegerCallable线程的call()运行结束并返回结果时为止.
- Integer returnInt = intFuture.get();
- System.out.println("返回值为" + returnInt);
- Future<Boolean> boolFuture = pool.submit(new BooleanCallable());
- Boolean returnBool = boolFuture.get();
- System.out.println("返回值为" + returnBool);
- pool.shutdown();
- }
- private final static class IntegerCallable implements Callable<Integer> {
- // call()方法的返回值类型由泛型决定
- @Override
- public Integer call() throws Exception {
- return 2;
- }
- }
- private final static class BooleanCallable implements Callable<Boolean> {
- @Override
- public Boolean call() throws Exception {
- return true;
- }
- }
- }
public class FutureDemo { public static void main(String[] args) throws Exception { ExecutorService pool = Executors.newFixedThreadPool(2); Future<Integer> intFuture = pool.submit(new IntegerCallable()); // get()方法将阻塞主线程, 直到IntegerCallable线程的call()运行结束并返回结果时为止. Integer returnInt = intFuture.get(); System.out.println("返回值为" + returnInt); Future<Boolean> boolFuture = pool.submit(new BooleanCallable()); Boolean returnBool = boolFuture.get(); System.out.println("返回值为" + returnBool); pool.shutdown(); } private final static class IntegerCallable implements Callable<Integer> { // call()方法的返回值类型由泛型决定 @Override public Integer call() throws Exception { return 2; } } private final static class BooleanCallable implements Callable<Boolean> { @Override public Boolean call() throws Exception { return true; } } }
程序的输出结果为:
返回值为2
返回值为true
|--List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks): 批量执行多个任务.
Future类. 如果需要获取线程的执行结果, 那么就会使用到Future. Future对象是一个指向异步执行结果的引用, 由于线程的异步特性, Future对象在其创建之初可能并不可用, 比如线程的call()方法尚未完成时. 可以调用Future对象的isDone()方法判断线程结果是否已经可用, 在线程结果返回之前调用Future对象的get()方法, 将导致阻塞.
关闭线程池. 使用完线程池后需要关闭它, 否则程序可能一直处于运行状态. ExecutorService提供了2个方法用于关闭线程池:
|--void shutdown(): 关闭线程池, 不再接受新任务. 如果存在正在执行的任务, 则等待任务执行完成.
|--List<Runnable> shutdownNow(): 关闭线程池, 不再接受新任务. 尽力尝试停止正在执行的任务, 并返回正在等待的任务列表.
|--boolean isShutdown(): 判断线程池是否已经关闭.
发表评论
-
Class.forName详解
2012-04-28 22:49 1038Class.forName详解 Class.forNa ... -
Java Serializable(序列化)的理解和总结
2012-03-23 10:01 887我对Java Serializable(序列化)的理解和总结 ... -
多线程
2011-11-28 15:36 0多线程 http://blog.csdn.net/ni ... -
Android I/O操作
2011-11-24 18:48 0Android I/O操作 http://book.5 ... -
Overload和Override的区别
2011-11-18 09:08 751Overload和Override的区别 方法的重写 O ...
相关推荐
阿里专家级并发编程架构师级课程,完成课程的学习可以帮助同学们解决非常多的JAVA并发编程疑难杂症,极大的提高JAVA并发编程的效率。课程内容包括了JAVA手写线程池,UC线程池API详解,线程安全根因详解,锁与原子类...
深入理解高并发编程-Java线程池核心技术 全面详解Java线程池核心技术
而了解 Java 并发编程以及其中的 JUC(java.util.concurrent)线程池,对于构建高性能、高可伸缩性的应用程序具有重要意义。 多核处理器的出现使得并发执行成为一种重要的优化手段。了解并发编程和线程池的工作原理...
java并发编程实战pdf 线程与多线程 1.线程 在操作系统中,线程是比进程更小的能够独立运行的基本单位。同时,它也是 CPU 调度的基本单位。线程本身基本上不拥有系统资源,只是拥有一些在运行时 需要用到的系统资源...
Java并发编程:线程池的使用 - 平凡希 - 博客园平凡希博客园首页联系管理随笔 - 127 文章 - 1 评论 - 94Java并发编程:线程池的使用在前面
当调用 start 启动线程时 Java 虚拟机会调 用该类的 run方法。 那么该类的 run() 方法中就是调用了 Runnable 对象的 run() 方法。 我 们可以继承重写Thread 类,在其 start 方法中添加不断循环调用传递过来的 ...
什么是Java中的面向对象编程(OOP)?列举OOP的原则。...什么是Java中的并发编程?列举一些常见的并发类和工具。 什么是Java中的线程池?如何创建和使用线程池? 什么是Java中的Callable和Future接口?如何使
阿里专家级并发编程架构师级课程,完成课程的学习可以帮助同学们解决非常多的JAVA并发编程疑难杂症,极大的提高JAVA并发编程的效率。课程内容包括了JAVA手写线程池,UC线程池API详解,线程安全根因详解,锁与原子类...
《Java并发编程的艺术》内容涵盖Java并发编程机制的底层实现原理、Java内存模型、Java并发编程基础、Java中的锁、并发容器和框架、原子类、并发工具类、线程池、Executor框架等主题,每个主题都做了深入的讲解,同时...
《Java并发编程从入门到精通》内容包括并发编程概念,线程,线程安全,线程集合类,线程阀,线程池,Fork/Join,线程、线程池在互联网项目开发的应用,线程监控及线程分析,Android中线程应用。 本书适合Java开发...
书籍:如《Java并发编程实战》、《Concurrency in C++》等。 官方文档:不同编程语言的官方文档通常会提供关于并发编程的指南和最佳实践。 社区和论坛:如Stack Overflow、Reddit等,可以提供实际问题的帮助和讨论。
1.1 并发简史 1.2 线程的优势 1.2.1 发挥多处理器的强大能力 1.2.2 建模的简单性 1.2.3 异步事件的简化处理 1.2.4 响应更灵敏的用户界面 1.3 线程带来的风险 1.3.1 安全性问题 1.3.2 活跃性问题 1.3.3 ...
Java并发编程的艺术 作者:方腾飞 魏鹏 程晓明 著 丛书名:Java核心技术系列 出版日期 :2015-07-25 ISBN:978-7-111-50824-3 第1章介绍Java并发编程的挑战,向读者说明进入并发编程的世界可能会遇到哪些问题,以及如何...
, 《Java并发编程的艺术》内容涵盖Java并发编程机制的底层实现原理、Java内存模型、Java并发编程基础、Java中的锁、并发容器和框架、原子类、并发工具类、线程池、Executor框架等主题,每个主题都做了深入的讲解,...
《Java并发编程实战》个人读书笔记,非常详细: 1 简介 2 线程安全性 3 对象的共享 4 对象的组合 5 基础构建模块 6 任务执行 7 取消与关闭 8 线程池的使用 9 图形用户界面应用程序 10 避免活跃性危险 11 性能与可...
java并发编程脑图总结,线程池、主要使用场景分析,进程:是CPU分配资源的最小单元,是程序的一次动态执行,它对应着从代码加载,执行至完成的一个完整的过程,它有自己的生命周期。它是应用程序的执行实例,每个...
23 高并发编程和线程池,教程视频:java中高并发编程和线程池
Java并发编程技术总结,所含内容有并发特性、并发锁、线程池、并发场景解决方案等,对于性能思考和内容参考资料有一定说明