服务器应用程序经常需要处理执行时间很短而数目巨大的请求, 如果为每一个请求创建一个新的线程, 会导致一些问题的出现, 如:
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.
01 | public class ExecutorsDemo { |
03 | public static void main(String[] args) throws Exception { |
04 | System.out.println( "----------------FixedThreadPool---------------------" ); |
05 | ExecutorService fixedPool = getFixedThreadPool(); |
06 | executeThread(fixedPool); |
11 | System.out.println( "----------------CashedThreadPool---------------------" ); |
12 | ExecutorService cashedPool = getCashedThreadPool(); |
13 | executeThread(cashedPool); |
18 | System.out.println( "----------------SingleThreadExecutor---------------------" ); |
19 | ExecutorService singleExecutor = getSingleThreadExecutor(); |
20 | executeThread(singleExecutor); |
25 | private static ExecutorService getSingleThreadExecutor() { |
26 | return Executors.newSingleThreadExecutor(); |
30 | private static ExecutorService getCashedThreadPool() { |
31 | return Executors.newCachedThreadPool(); |
35 | private static ExecutorService getFixedThreadPool() { |
36 | return Executors.newFixedThreadPool( 2 ); |
39 | private static void executeThread(ExecutorService pool) { |
40 | Thread t1 = new MyThread(); |
41 | Thread t2 = new MyThread(); |
42 | Thread t3 = new MyThread(); |
43 | Thread t4 = new MyThread(); |
54 | private static final class MyThread extends Thread { |
58 | 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()方法的返回值.
01 | public class FutureDemo { |
02 | public static void main(String[] args) throws Exception { |
03 | ExecutorService pool = Executors.newFixedThreadPool( 2 ); |
05 | Future<Integer> intFuture = pool.submit( new IntegerCallable()); |
06 | Integer returnInt = intFuture.get(); |
07 | System.out.println( "返回值为" + returnInt); |
09 | Future<Boolean> boolFuture = pool.submit( new BooleanCallable()); |
10 | Boolean returnBool = boolFuture.get(); |
11 | System.out.println( "返回值为" + returnBool); |
16 | private final static class IntegerCallable implements Callable<Integer> { |
19 | public Integer call() throws Exception { |
24 | private final static class BooleanCallable implements Callable<Boolean> { |
26 | public Boolean call() throws Exception { |
程序的输出结果为:
返回值为2
返回值为true
|--List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks): 批量执行多个任务.
关闭线程池. 使用完线程池后需要关闭它, 否则程序可能一直处于运行状态. ExecutorService提供了2个方法用于关闭线程池:
|--void shutdown(): 关闭线程池, 不再接受新任务. 如果存在正在执行的任务, 则等待任务执行完成.
|--List<Runnable> shutdownNow(): 关闭线程池, 不再接受新任务. 尽力尝试停止正在执行的任务, 并返回正在等待的任务列表.
|--boolean isShutdown(): 判断线程池是否已经关闭.
转自: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.
01 | public class ExecutorsDemo { |
03 | public static void main(String[] args) throws Exception { |
04 | System.out.println( "----------------FixedThreadPool---------------------" ); |
05 | ExecutorService fixedPool = getFixedThreadPool(); |
06 | executeThread(fixedPool); |
11 | System.out.println( "----------------CashedThreadPool---------------------" ); |
12 | ExecutorService cashedPool = getCashedThreadPool(); |
13 | executeThread(cashedPool); |
18 | System.out.println( "----------------SingleThreadExecutor---------------------" ); |
19 | ExecutorService singleExecutor = getSingleThreadExecutor(); |
20 | executeThread(singleExecutor); |
25 | private static ExecutorService getSingleThreadExecutor() { |
26 | return Executors.newSingleThreadExecutor(); |
30 | private static ExecutorService getCashedThreadPool() { |
31 | return Executors.newCachedThreadPool(); |
35 | private static ExecutorService getFixedThreadPool() { |
36 | return Executors.newFixedThreadPool( 2 ); |
39 | private static void executeThread(ExecutorService pool) { |
40 | Thread t1 = new MyThread(); |
41 | Thread t2 = new MyThread(); |
42 | Thread t3 = new MyThread(); |
43 | Thread t4 = new MyThread(); |
54 | private static final class MyThread extends Thread { |
58 | 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()方法的返回值.
01 | public class FutureDemo { |
02 | public static void main(String[] args) throws Exception { |
03 | ExecutorService pool = Executors.newFixedThreadPool( 2 ); |
05 | Future<Integer> intFuture = pool.submit( new IntegerCallable()); |
06 | Integer returnInt = intFuture.get(); |
07 | System.out.println( "返回值为" + returnInt); |
09 | Future<Boolean> boolFuture = pool.submit( new BooleanCallable()); |
10 | Boolean returnBool = boolFuture.get(); |
11 | System.out.println( "返回值为" + returnBool); |
16 | private final static class IntegerCallable implements Callable<Integer> { |
19 | public Integer call() throws Exception { |
24 | private final static class BooleanCallable implements Callable<Boolean> { |
26 | public Boolean call() throws Exception { |
程序的输出结果为:
返回值为2
返回值为true
|--List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks): 批量执行多个任务.
关闭线程池. 使用完线程池后需要关闭它, 否则程序可能一直处于运行状态. ExecutorService提供了2个方法用于关闭线程池:
|--void shutdown(): 关闭线程池, 不再接受新任务. 如果存在正在执行的任务, 则等待任务执行完成.
|--List<Runnable> shutdownNow(): 关闭线程池, 不再接受新任务. 尽力尝试停止正在执行的任务, 并返回正在等待的任务列表.
|--boolean isShutdown(): 判断线程池是否已经关闭.
转自:http://coolxing.iteye.com/blog/1236588
(转)java线程池的使用