在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