涉及到的
1)stack>vector>list
2)工厂模式, 单例模式
3)线程同步
4)泛型
5)反射
为什么要将对象池话,这个问题还是比较有意义的。我们知道,一个对象的生命周期包括:创建、使用、销毁(类比Servlet的生命周期)。实际上创建和使用之间还有一个初始化的过程,只不过java把初始化和创建这两步结合在了一起(思考题:为什么要这样设计java,这是如何实现的?)。
到了这里,我们会发现,真正我们关注的是对象的使用,而创建和销毁是为了适用对象而产生的额外开销,通常来讲,这个开销很小,可以忽略不计。但是如果一个程序中设计到很多的对象创建,并且创建时间比较长的话,那我们就会很明显的感觉到这部分所造成的系统速度受限。
到了这里,大家都会理解了池化的意义,就是对象使用完不销毁,而是存放起来,等着系统再次需要的时候直接拿出来。其思想就是这样:创建一次,使用多次,以空间换取时间。
注意到了有木有!“以空间换取时间”这种思想存在于程序设计的方方面面,不只是只有算法那些高大上的领域才用得到。
到了这里,可能大家都发现池化这么好。但是细心的人会考虑:那池化也是有代价的,它也是有时间和空间开销的。我为了解决刚才的问题而引入了新的开销,到底值不值?这是个很好的问题。
“对于类似Point这样的轻量级对象,进行池化处理后,性能反而下降,因此不宜池化;对于类似Hashtable这样的中量级对象,进行池化处理后,性能基本不变,一般不必池化(池化会使代码变复杂,增大维护的难度);对于类似JPanel这样的重量级对象,进行池化处理后,性能有所上升,可以考虑池化。
public class ObjectPool<T> {
private Stack<T> stack = new Stack<>();
private Integer minSize = 3;
private Integer maxSize = 10;
private Integer usedSize = 0;
private String classpath;
/**
* 考虑三种情况: stack中有object; stack中没有object,但是可以创建; stack中没有object,不能创建,只能等待归还
*/
public T getInstance() {
T t = null;
synchronized (stack) {
if (stack.size() > 0) {
t = stack.pop();
usedSize++;
} else if (usedSize < maxSize) {
try {
t = (T) Class.forName(classpath).newInstance();
usedSize++;
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// 当前要获取对象的线程等待,等待stack中有对象归还
else {
try {
stack.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 注意这里如果使用t = stack.pop()在线程调用多的情况下可能报错
t = getInstance();
}
}
return t;
}
public void returnInstance(T t) {
//对象归还时是否要对对象做初始化
synchronized(stack) {
stack.push(t);
usedSize--;
stack.notify();
}
}
public Integer getMinSize() {
return minSize;
}
public void setMinSize(Integer minSize) {
this.minSize = minSize;
}
public Integer getMaxSize() {
return maxSize;
}
public void setMaxSize(Integer maxSize) {
this.maxSize = maxSize;
}
public Integer getUsedSize() {
return usedSize;
}
public void setUsedSize(Integer usedSize) {
this.usedSize = usedSize;
}
public String getClasspath() {
return classpath;
}
public void setClasspath(String classpath) {
this.classpath = classpath;
}
}
public class TestMain {
public static void main(String[] args) {
ObjectPool<String> ss = new ObjectPool<>();
ss.setClasspath("java.lang.String");
for(int i = 0; i<20; i++) {
new Thread(new InnerThread(ss)).start();
}
}
static class InnerThread implements Runnable {
ObjectPool<String> ss;
public InnerThread(ObjectPool<String> ss) {
this.ss = ss;
}
@Override
public void run() {
// TODO Auto-generated method stub
String s = ss.getInstance();
s = Thread.currentThread().getName();
System.out.println(s);
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
s=null;
ss.returnInstance(s);
}
}
}