在JDK1.5版,Java标准包中就包含了对线程池的支持,提供了包java.lang.concurrent
.
1. ThreadPool
线程池是一个线程管理的集合,能够有效执行任务。当大量任务使用线程池执行时,由于线程循环的执行,整个性能得到提高,也减少了每个任务调用上的花费。实现线程池,你能够运用ExecutorService的实现类,比如ThreadPoolExecutor
或是ScheduledThreadPoolExecutor。另外,在类Executors
中提供了如下更方便的工厂方法:
Executors.newSingleThreadExecutor()
: 创建一个单一后台线程实例.Executors.newFixedThreadPool(int numThreads)
: 创建一个可以修复线程池大小实例.Executors.newCachedThreadPool()
:运用自动化线程回收利用来创建一个非绑定线程池实例。
使用线程池的步骤如下:
- 编写出实现了Runnable接口的工人线程类,run()方法指定了运行线程的行为。
- 使用由Executor类提供的工厂方法创建一个线程池(
ExecutorService
),这个线程池可以是 Executors.newSingleThreadExecutor(),或者Executors.newFixedThreadPool(int numThreads),也可以是Executors.newCachedThreadPool()创建的。 - 创建你的工人线程实例,使用execute(Runnable)方法去添加一个Runnable任务到线程池中。如何在池中有一个有效的线程,这个任务将会被调度并执行。
一个Executor对象能够执行Runnable提交的任务。Executor接口类(1.6version)中的方法:
- void execute(Runnable command);
它在不久的某个时间里执行一个给予任务。
接口ExecutorService定义了一些有用的方法,重要的两个如下:
- public void shutdown();
- // Initiates an orderly shutdown of the thread pool.
- // The previously executed/submitted tasks are allowed to complete,
- // but no new tasks will be scheduled.
- public <T> Future<T> submit(Callable<T> task);
- // Submit or schedule the callable task for execution, which returns a Future object.
Executors类中定义一些有用的方法:
- static ExecutorService newSingleThreadExecutor()
- static ExecutorService newFixedThreadPool(int nThreads)
- static ExecutorService newCachedThreadPool()
- static ScheduledExecutorService newSingleThreadScheduledExecutor()
- static ScheduledExecutorService newScheduledThreadPool(int size)
一个简单的例子来说明一下如何调用使用线程池。
- public class WorkerThread implements Runnable {
- private int workerNumber;
- WorkerThread(int workerNumber) {
- this.workerNumber = workerNumber;
- }
- public void run() {
- // The thread simply prints 1 to 5
- for (int i = 1; i <= 5; i++) {
- System.out.printf("Worker %d: %d\n", workerNumber, i);
- try {
- // sleep for 0 to 0.5 second
- Thread.sleep((int)(Math.random() * 500));
- } catch (InterruptedException e) {}
- }
- }
- }
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- public class ThreadPoolTest {
- public static void main(String[] args) {
- int numWorkers = Integer.parseInt(args[0]);
- int threadPoolSize = Integer.parseInt(args[1]);
- ExecutorService pool =
- Executors.newFixedThreadPool(threadPoolSize);
- WorkerThread[] workers = new WorkerThread[numWorkers];
- for (int i = 0; i < numWorkers; i++) {
- workers[i] = new WorkerThread(i+1);
- pool.execute(workers[i]);
- }
- pool.shutdown();
- }
- }
- Worker 1: 1
- Worker 2: 1
- Worker 2: 2
- Worker 2: 3
- Worker 2: 4
- Worker 1: 2
- Worker 1: 3
- Worker 2: 5
- Worker 1: 4
- Worker 1: 5
- Worker 3: 1
- Worker 3: 2
- Worker 4: 1
- Worker 3: 3
- Worker 3: 4
- Worker 4: 2
- Worker 3: 5
- Worker 4: 3
- Worker 5: 1
- Worker 4: 4
- Worker 5: 2
- Worker 5: 3
- Worker 4: 5
- Worker 5: 4
- Worker 5: 5
接口Callable和Runnable。
Callable与Runnable很相似。然而, Callable提供了一种能够固定在线程上的返回结果或是出现的异常。
- public V call()
- // Call() returns a result of type <V>, or throws an exception if unable to do so.
在线程池中,使用submit(Callable r)可以返回一个Future<V>(在
ExecutorService接口
类中声明
)对象。当需要有返回结果时,可以检索 get()方法来获得。如果不出现异常,会返回准备的结果。
Future<V>的方法如下:
- V get() // wait if necessary, retrieve result
- V get(long timeout, TimeUnit unit)
- boolean cancel(boolean mayInterruptIfRunning)
- boolean isCancelled()
- boolean isDone() // return true if this task completed
同样的例子,换一种写法:
- public class CallableWorkerThread implements Callable<String> {
- private int workerNumber;
- CallableWorkerThread(int workerNumber) {
- this.workerNumber = workerNumber;
- }
- public String call() { // use call() instead of run()
- for (int i = 1; i <= 5; i++) { // just print 1 to 5
- System.out.printf("Worker %d: %d\n", workerNumber, i);
- try {
- Thread.sleep((int)(Math.random() * 1000));
- } catch (InterruptedException e) {}
- }
- return "worker " + workerNumber;
- }
- }
- package org.concurrency.simple;
- /**
- * @author: John Liu
- */
- import java.util.concurrent.*;
- public class CallableThreadPoolTest {
- public static void main(String[] args) {
- int numWorkers = 5;
- ExecutorService pool = Executors.newCachedThreadPool();
- CallableWorkerThread workers[] = new CallableWorkerThread[numWorkers];
- Future[] futures = new Future[numWorkers];
- for (int i = 0; i < numWorkers; i++) {
- workers[i] = new CallableWorkerThread(i + 1);
- futures[i] = pool.submit(workers[i]);
- }
- for (int i = 0; i < numWorkers; i++) {
- try {
- System.out.println(futures[i].get() + " ended");
- } catch (InterruptedException ex) {
- ex.printStackTrace();
- } catch (ExecutionException ex) {
- ex.printStackTrace();
- }
- }
- }
- }
结果:
- Worker 2: 1
- Worker 4: 1
- Worker 5: 1
- Worker 1: 1
- Worker 3: 1
- Worker 4: 2
- Worker 4: 3
- Worker 2: 2
- Worker 4: 4
- Worker 5: 2
- Worker 1: 2
- Worker 3: 2
- Worker 4: 5
- Worker 5: 3
- Worker 2: 3
- Worker 5: 4
- Worker 3: 3
- Worker 1: 3
- Worker 2: 4
- Worker 1: 4
- Worker 3: 4
- Worker 5: 5
- Worker 2: 5
- Worker 1: 5
- Worker 3: 5
- worker 1 ended
- worker 2 ended
- worker 3 ended
- worker 4 ended
- worker 5 ended