java基础巩固-宇宙第一AiYWM:为了维持生计,享元模式阅读总结【在JDK的包装类中、】~整起

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

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;
			}
		}
	}
}

可以测试,也就是使用连接池时像下面一样:
java基础巩固-宇宙第一AiYWM:为了维持生计,享元模式阅读总结【在JDK的包装类中、】~整起_第1张图片
用Semaphore信号量升级一下,用来限制能同时访问共享资源的线程上限
java基础巩固-宇宙第一AiYWM:为了维持生计,享元模式阅读总结【在JDK的包装类中、】~整起_第2张图片

巨人的肩膀:
B战各位老师
设计模式之禅
head first设计模式

你可能感兴趣的:(设计模式~学了个学,java,享元模式,缓存,设计模式)