PART1:享元模式~Flyweight pattern
- 应用场景:.当需要
重用数量有限的同一类对象
时,而不是我们每次都要创建一个新的来使用 - 谁都用到了享元模式呢?
- JDK的包装类中的valueOf()中就用到了享元模式:在JDK中Boolean, Byte, Short, Integer, Long, Character 等包装类提供了valueOf方法,
例如Long的valueOf会缓存-128~127之间的Long对象,在这个范围之间会重用对象,大于这个范围,才会新建Long对象
:避免了长整形Long对象的重复创建public static Long value0f(long 1) { final int offset = 128; //也就是-128到127范围内的256个可以重复使用,出了这个范围就得新实例化创建了 if(1>=-128&&1<=127){//will cache //从缓存数组中获取长整形对象 return LongCache.cache[(int)1 + offset] ; } return new Long(1); } //静态内部类LongCache private static class LongCache { private LongCache(){} //LongCache 初始化时就会创建一个大小为256的长整形Long包装类对象的数组cache[] static final Long cache[] = new Long[-(-128) + 127 + 1]; //在初始化代码模块里 static { for(int i = 0; i < cache.length; i++){ //事先把这256个对象全部都提前创建好,存入cache数组中 cache[i] = new Long( value: i - 128); } } }
- Byte, Short, Long缓存的范围都是-128~127
- Character缓存的范围是0~ 127
- Integer的默认范围是-128~127,最小值不能变,但最大值可以通过调整虚拟机参数:-Djava. lang. Integer. IntegerCache . high来改变
- Boolean缓存了TRUE和FALSE
- JDK的包装类中的valueOf()中就用到了享元模式:在JDK中Boolean, Byte, Short, Integer, Long, Character 等包装类提供了valueOf方法,
PART2:diy连接池,使用一下享元模式
- 一个线上商城应用,
QPS 达到数干,如果每次都重新创建和关闭数据库连接,性能会受到极大影响
。这时预先创建好一批连接,放入连接池。一次请求到达后,从连接池获取连接,使用完毕后再还回连接池,这样既节约了连接的创建和关闭时间,也实现了连接的重用
,不至于让庞大的连接数压垮数据库
。
class Pool {
//1.连接池大小
private final int poolSize ;
//2.连接对象数组
private Connection[] connections ;
//3.连接状态数组0表示空闲,1表示繁忙
private AtomicIntegerArray states;
//4.构造方法初始化
public Pool(int poolSize) {
this.poolSize = poolSize;
//让许可数与资源数一致
this.semaphore = new Semaphore(poolSize);
this.connections = new Connection[poolSize];
this.states = new AtomicIntegerArray(new int[poolSize]);
for (int i = 0; i < poolSize; i++) {
connections[i] = new MockConnection();
}
}
//5.借连接
public Connection borrow() {
while(true) {
for(int i = 0; i < poolSize; i++) {
//获取空闲连接
if(states.get(i) == 0) {
//只能让一个线程成功另一个线程失败,不就指明了用CAS嘛。用CAS把下表为i的元素从0改为1.第二个线程再想改就不行了,因为已经改为1了不满足CAS的比较条件了
//CAS适合短时间的代码操作,不停歇的情况下利用CPU去获取锁
if(states.compareAndSet(i, expect: 0,update: 1)){
return connections[i];
}
}
}
//如果没有空闲连接,当前线程进入等待
synchronized(this) {
try{
this.wait();
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}
//6.归还连接
public void free(Connection conn) {
//换的是我原来的连接吗,别还一个坏的回来,我不是亏了
for (int i = 0; i < poolSize; i++) {
if(connections[i] == conn) {
states.set(i, 0);
synchronized (this) {
this.notifyA1ll();
}
break;
}
}
}
}
可以测试,也就是使用连接池时像下面一样:
用Semaphore信号量升级一下,用来限制能同时访问共享资源的线程上限
巨人的肩膀:
B战各位老师
设计模式之禅
head first设计模式