ThreadPoolExecutor的构造函数接受一个参数,是ThreadFactory,这是一个用于创建线程的工厂。工厂模式做为Java各种框架中使用最频繁的一种设计模式,所以下面好好讲讲这一内容。
从例子开始
工厂模式是设计模式中最简单,最容易理解的一种模式,因为它是和现实直接挂勾,是对现实的直接模拟。举一个例子,假如,现在有一个工厂,可以生产鼠标,键盘,摄像头。做为顾客,要从这个工厂中获得具体的产品,我们其实是不想知道这些产品在工厂中是如何被创建的。我们所希望的是,通过这个工厂的一个接口,就可以获得这些产品。
我们先定义键盘如下:
public interface Device {
void setModel(int model);
int getModel();
void setSize(int size);
int getSize();
}
class KeyBoard implements Device {
int model;
int size;
@Override
public void setModel(int model) {
this.model = model;
}
@Override
public int getModel() {
return model;
}
@Override
public void setSize(int size) {
this.size = size;
}
@Override
public int getSize() {
return size;
}
}
鼠标和摄像头也是同样的定义,这里就不再列出了。如果,我们使用这个定义来写代码,就要这样写:
Device d = new KeyBoard();
d.setModel(1);
d.setSize(5);
看上去好像还可以,但如果,将来keyBoard的定义发生改变了,比如增加一个字段,来表示keyBoard是不是机械键盘,那么所有使用KeyBoard的构造函数的地方,都要修改,这肯定是很不好的,所以,我们可以想办法,把这些东西封装起来。
这里要介绍的方法就是工厂方法。我们可以通过在中间引入一层抽象。做为客户端我们只要去访问这个中间层的特定方法就好了。例如:
public class DeviceFactory {
public Device getProduct(String name) {
if (name.equals("keyboard")) {
Device d = new KeyBoard();
d.setModel(1);
d.setSize(5);
return d;
}
else if (name.equals("mouse")) {
return new Mouse();
}
else if (name.equals("camera")) {
return new Camera();
}
else
return null;
}
}
// 客户端程序
public static void main(String[] args) {
DeviceFactory factory = new DeviceFactory();
KeyBoard keyBoard = (KeyBoard) factory.getProduct("keyboard");
}
即使将来,KeyBoard的定义发生了变化,我们不必修改客户端程序。KeyBoard的生产流程,工厂去关心就好了,做为用户,我们就不应该关心:
lass KeyBoard implements Device {
int model;
int size;
boolean isMechanical;
//....其他定义略去
public void setMechanical(boolean isMechanical) {
this.isMechanical = isMechanical;
}
}
相应的工厂变成这样:
public class DeviceFactory {
public Device getProduct(String name) {
if (name.equals("keyboard")) {
KeyBoard d = new KeyBoard();
d.setModel(1);
d.setSize(5);
d.setMechanical(true);
return d;
}
//...其他略去
}
}
通过这一层抽象,我们就把客户端与具体的产品建造过程分隔开了。这种模式就是工厂模式。总结一下,工厂模式就是引入一个工厂类,由它来负责某些具体类的创建和构造。
ThreadFactory
昨天我们讲到了ThreadFactory,我们来看一下JDK源码,在知道了工厂模式之后,这种命名,以及它们的结构,就毫无秘密可言了:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
这里使用了defaultThreadFactory做为参数,那我们继续看defaultThreadFactory是什么样的:
public static ThreadFactory defaultThreadFactory() {
return new DefaultThreadFactory();
}
static class DefaultThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
DefaultThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = "pool-" +
poolNumber.getAndIncrement() +
"-thread-";
}
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
if (t.isDaemon())
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
很显然,newThread方法就是这个工厂类的工厂方法,真正创建线程的地方就在这里。
比如说,如果我们现在希望使用一个线程池,这个线程池里的线程的调度优先级变高或者变低,那么我们就只需要重新定义一个线程工厂,在工厂方法中把线程的优先级调高或者调低就可以了。