百度联盟怎么做网站,淘宝网站是谁做的好处,wordpress的文件夹,国家网站备案目录 1 什么是单例模式#xff1f;1.1 什么是饿汉式#xff1f;1.2 什么是懒汉式#xff1f; 2 我对饿汉式的思考3 懒汉式3.1 解决懒汉式的线程安全问题3.1.1 加锁#xff1a;synchronized#xff08;synchronized修饰静态方法#xff09;3.1.2 对“3.1.1”性能的改进 1 … 目录 1 什么是单例模式1.1 什么是饿汉式1.2 什么是懒汉式 2 我对饿汉式的思考3 懒汉式3.1 解决懒汉式的线程安全问题3.1.1 加锁synchronizedsynchronized修饰静态方法3.1.2 对“3.1.1”性能的改进 1 什么是单例模式
单例模式是指一个类在JVM中只有一个实例。
1.1 什么是饿汉式
在类加载的时候就创建好了实例。
1.2 什么是懒汉式
创建实例延迟到使用该实例前。
2 我对饿汉式的思考
示例
public class LearnSingleton {private static LearnSingleton instance new LearnSingleton();private LearnSingleton() {}public static LearnSingleton getInstance() {return instance;}
}当我们调用LearnSingleton.getInstance()时会触发LearnSingleton的加载。在类加载的准备阶段创建好了静态变量表此时instance对应的slot槽还为null等到了初始化阶段开始执行clinit方法会创建LearnSingleton的示例执行了new LearnSingleton()语句。类加载后执行getInstance()方法将单例返回给用户。 这么一看上述写法不也是懒汉式吗在使用时才创建实例啊。虽然这个实例也是在类加载时就创建好的 要想明白这到底是懒汉式还是饿汉式关键在于
public class LearnSingleton {private static LearnSingleton instance new LearnSingleton();private LearnSingleton() {}public static LearnSingleton getInstance() {return instance;}public static int add(int x, int y) {return x y;}
}当用户调用LearnSingleton.add(1, 2)时在类加载过程中就已经创建好了单例但并未使用。因此这不符合在需要时创建单例的定义。从这个例子就能想明白了这种写法是饿汉式。彻底的饿汉式
public class LearnSingleton {private static final LearnSingleton instance new LearnSingleton();private LearnSingleton() {}public static LearnSingleton getInstance() {return instance;}
}只要这个类加载了由于instance是常量因此在类加载的准备阶段就创建好了单例。这是彻底的饿汉式。可谓“饿疯了”。饿汉式是在类加载阶段完成实例的创建由JVM保证了线程安全。
3 懒汉式
在调用时才创建对象示例
public class LearnLazySingleton {private static LearnLazySingleton instance;private LearnLazySingleton() {}// 存在线程安全问题。假设两个线程同时调用该方法那么可能导致创建2个LearnLazySingleton对象。public static LearnLazySingleton getInstance() {if (instance null) {instance new LearnLazySingleton();}return instance;}
}3.1 解决懒汉式的线程安全问题
3.1.1 加锁synchronizedsynchronized修饰静态方法
public class LearnLazySingleton {private static LearnLazySingleton instance;private LearnLazySingleton() {}public synchronized static LearnLazySingleton getInstance() {if (instance null) {instance new LearnLazySingleton();}return instance;}public synchronized static int add(int x, int y) {return x y;}public static int sub(int x, int y) {return x - y;}
}当线程A先调用getInstance()方法的同时 另一个线程B尝试访问add()方法线程B会因为没有LearnLazySingleton的class对象的锁而等待。如果类中的其他方法不是synchronized的它们就不会被锁定即线程C调用sub方法()就不会等待。 本质是因为在调用同步方法前只有获取锁才能进入临界区。而如果不是临界区那就不会受影响。
3.1.2 对“3.1.1”性能的改进
上面的写法有个非常难受的地方例如线程A已经调用getInstance()方法创建好了单例。但线程B为了获取单例也不得不调用getInstance()方法唯一获取实例的入口这时候就可能和线程C撞车因为只要线程C调用add方法()就可能让线程B获取单例时发生阻塞。改进
public class LearnLazySingleton {private static LearnLazySingleton instance;private LearnLazySingleton() {}public static LearnLazySingleton getInstance() {if (instance null) {synchronized (LearnLazySingleton.class) {// 这里一旦要在判断下否则线程A和线程B在这里排队进入临界区会导致创建多个实例。if (instance null) {instance new LearnLazySingleton();}}}return instance;}public synchronized static int add(int x, int y) {return x y;}
}在创建单例前仍然存在线程A和线程B争抢着执行“instance new LearnLazySingleton();”也会影响线程C去调用add()方法。但一旦实例创建好后instance不为null线程们调用getInstance()方法就不会阻塞了。