线程池

前言

通常情况下,要执行的任务是短暂的,而且任务的数量很大。 为每个任务创建一个新的线程将使系统花费更多的时间创建和销毁线程,却不能保证执行实际的任务。 线程池通过重用现有的线程来解决这个问题并消除了创建新线程的延迟。

适用性

当您有大量的短期任务需要并行执行时,可以考虑用线程池

本文举例

假设有两个任务: 土豆去皮任务和制作咖啡任务,当对这两个任务量化执行时,可以考虑用线程池去完成。

alt text
Task.java: 任务抽象类

public abstract class  {

private static final AtomicInteger ID_GENERATOR = new AtomicInteger();

private final int id;
private final int timeMs;

public (final int timeMs) {
this.id = ID_GENERATOR.incrementAndGet();
this.timeMs = timeMs;
}

public int getId() {
return id;
}

public int getTimeMs() {
return timeMs;
}


public String toString() {
return String.format("id=%d timeMs=%d", id, timeMs);
}
}

Worker.java: 任务执行类

public class Worker implements Runnable {

private static final Logger LOGGER = LoggerFactory.getLogger(Worker.class);

private final Task task;

public Worker(final Task task) {
this.task = task;
}


public void run() {
LOGGER.info("{} 正在处理任务: [{}]", Thread.currentThread().getName(), task.toString());
try {
Thread.sleep(task.getTimeMs());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

PotatoPeelingTask.java:土豆去皮任务


*
* 土豆去皮任务
*
*/
public class PotatoPeelingTask extends {


* 每个土豆去皮的时间
*/
private static final int TIME_PER_POTATO = 200;

public PotatoPeelingTask(int numPotatoes) {
super(numPotatoes * TIME_PER_POTATO);
}


public String toString() {
return String.format("%s %s", this.getClass().getSimpleName(), super.toString());
}
}

CoffeeMakingTask.java:咖啡制作任务


*
* 制作咖啡任务
*
*/
public class CoffeeMakingTask extends {


* 每杯咖啡制作时间
*/
private static final int TIME_PER_CUP = 100;

public CoffeeMakingTask(int numCups) {
super(numCups * TIME_PER_CUP);
}


public String toString() {
return String.format("%s %s", this.getClass().getSimpleName(), super.toString());
}
}

App.java:程序入口

public static void main(String[] args) {

LOGGER.info("Program started");

// Create a list of tasks to be executed
List<Task> tasks = new ArrayList<>();
tasks.add(new PotatoPeelingTask(3));
tasks.add(new PotatoPeelingTask(6));
tasks.add(new CoffeeMakingTask(2));
tasks.add(new CoffeeMakingTask(6));
tasks.add(new PotatoPeelingTask(4));
tasks.add(new CoffeeMakingTask(2));
tasks.add(new PotatoPeelingTask(4));
tasks.add(new CoffeeMakingTask(9));
tasks.add(new PotatoPeelingTask(3));
tasks.add(new CoffeeMakingTask(2));
tasks.add(new PotatoPeelingTask(4));
tasks.add(new CoffeeMakingTask(2));
tasks.add(new CoffeeMakingTask(7));
tasks.add(new PotatoPeelingTask(4));
tasks.add(new PotatoPeelingTask(5));

// Creates a thread pool that reuses a fixed number of threads operating off a shared
// unbounded queue. At any point, at most nThreads threads will be active processing
// tasks. If additional tasks are submitted when all threads are active, they will wait
// in the queue until a thread is available.
ExecutorService executor = Executors.newFixedThreadPool(3);

// Allocate new worker for each task
// The worker is executed when a thread becomes
// available in the thread pool
for (int i = 0; i < tasks.size(); i++) {
Runnable worker = new Worker(tasks.get(i));
executor.execute(worker);
}
// All tasks were executed, now shutdown
executor.shutdown();
while (!executor.isTerminated()) {
Thread.yield();
}
LOGGER.info("Program finished");
}
}

运行结果:


23:33:24.952 [main] INFO com.iluwatar.threadpool.App - Program started
23:33:24.968 [pool-1-thread-1] INFO com.iluwatar.threadpool.Worker - pool-1-thread-1 正在处理任务: [PotatoPeelingTask id=1 timeMs=600]
23:33:24.968 [pool-1-thread-3] INFO com.iluwatar.threadpool.Worker - pool-1-thread-3 正在处理任务: [CoffeeMakingTask id=3 timeMs=200]
23:33:24.968 [pool-1-thread-2] INFO com.iluwatar.threadpool.Worker - pool-1-thread-2 正在处理任务: [PotatoPeelingTask id=2 timeMs=1200]
23:33:25.176 [pool-1-thread-3] INFO com.iluwatar.threadpool.Worker - pool-1-thread-3 正在处理任务: [CoffeeMakingTask id=4 timeMs=600]
23:33:25.575 [pool-1-thread-1] INFO com.iluwatar.threadpool.Worker - pool-1-thread-1 正在处理任务: [PotatoPeelingTask id=5 timeMs=800]
23:33:25.778 [pool-1-thread-3] INFO com.iluwatar.threadpool.Worker - pool-1-thread-3 正在处理任务: [CoffeeMakingTask id=6 timeMs=200]
23:33:25.981 [pool-1-thread-3] INFO com.iluwatar.threadpool.Worker - pool-1-thread-3 正在处理任务: [PotatoPeelingTask id=7 timeMs=800]
23:33:26.169 [pool-1-thread-2] INFO com.iluwatar.threadpool.Worker - pool-1-thread-2 正在处理任务: [CoffeeMakingTask id=8 timeMs=900]
23:33:26.388 [pool-1-thread-1] INFO com.iluwatar.threadpool.Worker - pool-1-thread-1 正在处理任务: [PotatoPeelingTask id=9 timeMs=600]
23:33:26.795 [pool-1-thread-3] INFO com.iluwatar.threadpool.Worker - pool-1-thread-3 正在处理任务: [CoffeeMakingTask id=10 timeMs=200]
23:33:26.998 [pool-1-thread-1] INFO com.iluwatar.threadpool.Worker - pool-1-thread-1 正在处理任务: [CoffeeMakingTask id=12 timeMs=200]
23:33:26.998 [pool-1-thread-3] INFO com.iluwatar.threadpool.Worker - pool-1-thread-3 正在处理任务: [PotatoPeelingTask id=11 timeMs=800]
23:33:27.076 [pool-1-thread-2] INFO com.iluwatar.threadpool.Worker - pool-1-thread-2 正在处理任务: [CoffeeMakingTask id=13 timeMs=700]
23:33:27.201 [pool-1-thread-1] INFO com.iluwatar.threadpool.Worker - pool-1-thread-1 正在处理任务: [PotatoPeelingTask id=14 timeMs=800]
23:33:27.780 [pool-1-thread-2] INFO com.iluwatar.threadpool.Worker - pool-1-thread-2 正在处理任务: [PotatoPeelingTask id=15 timeMs=1000]
23:33:28.781 [main] INFO com.iluwatar.threadpool.App - Program finished

可以看到,线程池创建了三个线程,并行的执行任务,当有空闲线程时,可以被复用,继续执行任务.