为什么要使用线程池?
启动一个线程是一件很耗资源的事情, 启动线程需要跟底层操作系统打交道,为新线程开辟一个资源空间. 此外,一个进程中,线程过多,会耗尽资源,导致系统崩溃. 所以,重用和控制线程数量,是线程的必要知识.
Executors
J2ME中的java.util.concurrent.Executors就是一个线程执行器工厂,这个执行器可以管理线程池. Executors应该算是一个工厂,使用它类似newInstance的方法,可以创造出各种功能的ExecutorService(interface)实例. ExecutorService是Executor的继承接口.它的实例也就是线程执行器.
下面来看看Executors能产生什么功能的Executor实例.
newFixedThreadPool() - 创造一个管理固定数量线程的线程池.
newCachedThreadPool() - 创造一个管理非固定数量的线程池,线程一旦结束一段时间,则销毁.
newSingleThreadExecutor() - 产生一个单线程的执行器.
newSingleScheduledThreadExecutor() - 产生一个scheduled单线程执行器.
newScheduledThreadPool() - 创造一个scheduled线程的线程池.
有了Executor或者ExecutorService以后,怎么调用线程呢?
用例
一个厕所有3个坑,人们不停的进厕所做enen的事情.排量随机,蹲坑时间随机. 厕所的容量(capacity)为100, 当厕所的排量(volume)超过容量的时候, 通知清洁工来清洁. 清洁过程中不能再放新人进来. 厕所每天只服务100个人,然后停业.
本例中有4个类:
ThreadPool - main函数入口类.
Toilet - 厕所, 它使用一个具有3个线程处理能力的线程池来表达3个坑(holes)的概念.
People - 人, 排队上厕所
Cleaner - 清洁工, 清扫厕所
package concurrency;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolTest {
public static void main(String[] args) {
new ThreadPoolTest().test();
}
private void test() {
Toilet toilet = new Toilet();
boolean allowed = true;
for (int i=0; allowed; i++) {
People p = new People(i+"", toilet);
allowed = toilet.allowIn(p);
}
}
private class Toilet {
private volatile boolean cleaning = false;
private volatile int volume=0;
private final int CAPACITY = 100;
private volatile int peopleIn = 0;
private volatile int count = 0;
private Cleaner cleaner;
// 3 holes in his toilet.
private ExecutorService holes = Executors.newFixedThreadPool(3);
private Toilet() {
this.cleaner = new Cleaner(this);
}
private synchronized boolean allowIn(Runnable people) {
// If toilet is cleaning or 3 holes are taken, wait.
while (this.cleaning == true || this.peopleIn >= 3 ) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// Only serves 100 people one day.
if (count > 100) {
this.holes.shutdown();
return false;
} else {
this.peopleIn(((People)people).name);
holes.submit(people);
return true;
}
}
private synchronized void enEn(String name, int v) {
this.volume += v;
System.out.println("People["+name+"] put in ["+v+"]. Toilet volume increases to ["+volume+"]");
// If the volume exceeds capacity, notify cleaner to clean.
if (this.volume > this.CAPACITY) {
this.notifyCleaner();
}
}
private void notifyCleaner() {
if (this.cleaning == false) {
System.out.println("Toilet volume full with ["+volume+"]. Notify cleaner.");
holes.submit(cleaner);
}
}
private synchronized void peopleIn(String name) {
System.out.println("People["+name+"] comes in.");
this.peopleIn ++;
this.count++;
}
private synchronized void peopleOut(String name) {
System.out.println("People["+name+"] comes out.");
this.peopleIn --;
this.notifyAll();
}
public synchronized void cleaning() {
this.cleaning = true;
}
public synchronized void cleaned() {
this.cleaning = false;
this.notifyAll();
}
}
// One toilet cleaner.
private class Cleaner implements Runnable {
private Toilet toilet;
private Cleaner(Toilet t) {
this.toilet = t;
}
@Override
public void run() {
toilet.cleaning();
System.out.println("Toilet Cleaning...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.toilet.volume = 0;
System.out.println("Toilet Clean done.");
toilet.cleaning = false;
toilet.cleaned();
}
}
private class People implements Runnable {
private Toilet toilet;
private String name;
private People(String name, Toilet t) {
this.toilet = t;
this.name = name;
}
@Override
public void run() {
System.out.println("People["+name+"] is en en en...");
try {
Thread.sleep(new Random().nextInt(500));
} catch (InterruptedException e) {
e.printStackTrace();
}
toilet.enEn(name, new Random().nextInt(11));
toilet.peopleOut(name);
}
}
}