享元模式(Flyweight Pattern)是池技术的重要实现方式。其宗旨是共享细粒度对象,将多个对同一对象的访问集中起来,不必为每个访问者都创建一个单独的对象,以此来降低内存的消耗,属于结构型设计模式。
享元模式把一个对象的状态分成内部状态和外部状态,内部状态是不变的,外部状态是变化的;然后通过共享不变的部分,达到减少对象数量并节约内存的目的。
- 内部状态 对象共享的部分,存储在享原对象内部并且不会随环境改变而改变。
- 外部状态 对象不共享的部分,依赖的标记,随环境改变而改变的、不可共享的状态。id,唯一索引。

具体享原角色的内部状态处理应该与环境无关,不会出现一个操作改变内部状态、同时修改了外部状态的情况
public interface IFlyWeight {void op(String extrinsicState);}public class FlyWeightA implements IFlyWeight{//内部状态private String intrinsicState;public FlyWeightA(String intrinsicState) {this.intrinsicState = intrinsicState;}@Overridepublic void op(String extrinsicState) {System.out.println(extrinsicState);}}public class FlyWeightFactory {private static Map<String,IFlyWeight> pool = new HashMap<>();public static IFlyWeight getFlyWeight(String intrinsicState){if(pool.containsKey(intrinsicState)){return pool.get(intrinsicState);}else {IFlyWeight iFlyWeight = new FlyWeightA(intrinsicState);pool.put(intrinsicState,iFlyWeight);return iFlyWeight;}}}
优点
大大减少应用程序创建的对象,降低程序内存的占用,增强程序的性能
缺点
- 提高了系统复杂性,需要分离出外部状态和内部状态,而且外部状态具有固化特性,不应该随内部状态改变而改变,否则导致系统的逻辑混乱。
- 线程安全问题
场景
- 系统中存在大量的相似对象。
- 细粒度的对象都具备较接近的外部状态,而且内部状态与环境无关,也就是说对象没有特定身份。
- 需要缓冲池的场景。
框架
- String
String是被final修饰的不可变类,字符串常量保存在字符串常量池,jdk6及以前保存在方法区,jdk7以后字符串常量池在堆上。
当以字面量的形式创建String变量时,JVM会在编译期间就把该字面量放到字符串常量池中,在Java启动的时候就已经加载到内存中了。这个字符串常量池的特点就是有且只有一份相同的字面量。如果有其他相同的字面量,则JVM返回这个字面量的引用;如果没有相同的字面量,则在字符串常量池中创建这个字面量并返回它的引用。
String s3 = “he”+”llo”;这样的拼接会在编译期间被优化成”hello”,创建在字符串常量池
String s4 = “he”;
String s5 = “llo”;
String s6 = s4 + s5;这样的拼接不会被优化,本质上是StringBuilder的拼接,创建在堆上
intern()方法能使一个位于堆中的字符串在运行期间动态地加入字符串常量池(字符串常量池的内容是在程序启动的时候就已经加载好了的)。如果字符串常量池中有该对象对应的字面量,则返回该字面量在字符串常量池中的引用(如果字符串常量是堆对象intern放进去的,字符串常量池保存的是指向堆对象的引用;如果字符串常量是字面量放进去的,字符串常量池保存的是字面量对象);否则,复制一份该字面量到字符串常量池并返回它的引用。
- Integer.valueOf()
-128~127读缓存, 因为-128~127的数据在int范围内是使用最频繁的,为了减少频繁创建对象带来的内存消耗,这里就用到了享元模式,以提高性能
public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);}
- Apache Pool
对象池化的基本思路是:将用过的对象保存起来,等下一次需要这种对象的时候,再拿出来重复使用,从而在一定程度上减少频繁创建对象造成的消耗。用于充当保存对象的“容器”的对象,被称为对象池(Object Pool,简称Pool)。
Apache Pool实现了对象池的功能,定义了对象的生成、销毁、激活、钝化等操作及其状态转换,并提供几个默认的对象池实现,有如下几个重要的角色。
