单例设计模式与类加载顺序详解


单例设计模式几种实现 (测试所用jdk版本1.8.0_20)

第一种:

 1 public final class SingleInstance1 {
2
3 private static volatile SingleInstance1 singleInstance = null;
4 /*
5 * 必须定义,防止jvm提供默认构造函数(默认的为public)这样就失去了单例的特性,
6 * 因为可以new一个实例
7 */
8 private SingleInstance1(){}
9 public static SingleInstance1 getInstance(){
10 if(singleInstance == null){
11 synchronized (SingleInstance1.class) {
12 if(singleInstance == null){
13 singleInstance = new SingleInstance1();
14 }
15 }
16 }
17 return singleInstance;
18 }
19 }
View Code

这种模式是单锁,有线程安全问题 所以用两把锁

第二种:

 1 /**
2 *
3 * 说明:线程安全的单例
4 *
5 */
6 public final class SingleInstance2 {
7
8 private static volatile SingleInstance2 singleInstance = null;
9
10 /*
11 * 必须定义,防止jvm提供默认构造函数(默认的为public)这样就失去了单例的特性, 因为可以new一个实例
12 */
13 private SingleInstance2() {
14 }
15
16 public static SingleInstance2 getInstance() {
17 if (singleInstance == null) {
18 synchronized (SingleInstance2.class){
19 SingleInstance2 tmpInstance2 = singleInstance;
20 synchronized (SingleInstance2.class) {
21 if (tmpInstance2 == null) {
22 tmpInstance2 = new SingleInstance2();
23 }
24 singleInstance = tmpInstance2;
25 }
26 }
27 }
28 return singleInstance;
29 }
30 }
View Code

第三种:

 1 /**
2 *
3 * 说明:饿汉式 不是线程安全的
4 *
5 */
6 public class SingleInstance3 {
7 private static SingleInstance3 singleInstance = null;
8
9 private SingleInstance3(){}
10
11 public SingleInstance3 getInstance3() {
12 if(singleInstance == null) {
13 singleInstance = new SingleInstance3();
14 }
15 return singleInstance;
16
17 }
18
19 }
View Code

第四种:

 1 /**
2 *
3 * 说明:懒汉式 缺点:每个对象在没有使用之前就已经初始化了。这就可能带来潜在的性能问题
4 * 没有使用这个对象之前,就把它加载到了内存中去是一种巨大的浪费
5 */
6 public class SingleInstance4 {
7 private static SingleInstance4 singleInstance = new SingleInstance4();
8
9 private SingleInstance4() {
10 }
11
12 public SingleInstance4 getInstance() {
13 return singleInstance;
14 }
15
16 }
View Code

第五种:

 1 /**
2 *
3 *说明:线程安全 但是效率低,因为只需要创建时同步就可以了 不需要每次访问都要同步
4 */
5 public class SingleInstance5 {
6 private static SingleInstance5 singleInstance5 = null;
7 private SingleInstance5() {
8 }
9
10 public static synchronized SingleInstance5 getInstance5(){
11 if(singleInstance5 == null){
12 singleInstance5 = new SingleInstance5();
13 }
14 return singleInstance5;
15 }
16 }
View Code

第六种:

 1 /**
2 *
3 *内部类静态属性(或静态块)会在内部类第一次被调用的时候按顺序被初始化(或执行)而且只会被加载一次
4 *测试请看StaticInnerClassLoaderTime类
5 */
6 public class SingleInstance6 {
7 private SingleInstance6() {}
8 private static class SingletonHolder {
9 public final static SingleInstance6 instance = new SingleInstance6();
10 }
11
12 public static SingleInstance6 getInstance() {
13 return SingletonHolder.instance;
14 }
15
16 }
View Code

StaticInnerClassLoaderTime类

 1 public class StaticInnerClassLoaderTime {
2
3 public static class Inner {
4 static {
5 System.out.println("TestInner Static!");
6 }
7 public final static StaticInnerClassLoaderTime testInstance =
8 new StaticInnerClassLoaderTime(3);
9 }
10
11 public static StaticInnerClassLoaderTime getInstance() {
12 return Inner.testInstance;
13 }
14
15 public StaticInnerClassLoaderTime(int i) {
16 System.out.println("Test " + i + " Construct! ");
17 }
18
19
20 // 类静态属性
21 public static StaticInnerClassLoaderTime testOut =
22 new StaticInnerClassLoaderTime(1);
23
24 public static int value = 3;
25 // 类静态块
26 static {
27 System.out.println("Test Static" + testOut);
28 }
29
30 public static void main(String args[]) {
31 StaticInnerClassLoaderTime t = new StaticInnerClassLoaderTime(2);
32 //说明静态内部类只有在调用时才会被加载 而且只会被加载一次 因此最好的单例设计模式是用静态内部类
33 StaticInnerClassLoaderTime.getInstance();
34 StaticInnerClassLoaderTime.getInstance();
35 }
36
37 }
View Code

运行结果:

1 Test 1 Construct!
2 Test Staticcn.canon.Single.StaticInnerClassLoaderTime@15db9742
3 Test 2 Construct!
4 TestInner Static!
5 Test 3 Construct!
View Code

说明:

 顺序是:父类静态属性-》父类静态代码块-》子类静态变量-》子类静态代码块-》父类非静态变量-》父类非静态代码块-》父类构造函数-》
 子类非静态变量-》子类非静态代码块-》-》子类构造函数

这样的加载顺序不是绝对的 因为静态变量和静态代码块跟声明顺序有关。

对于如果静态代码块中调用静态变量,那么静态变量必须在静态代码块前面声明;如果静态代码块中没有调用静态变量,
那么就跟顺序有关了,谁先声明谁先被加载。说白了还是顺序加载,之所以会出现“如果静态代码块中调用静态变量,
那么静态变量必须在静态代码块前面声明”,是因为变量是声明,所以出现编译错误。

应用到内部类中 静态变量和静态代码块跟声明顺序有关。 这样就可以解释你的问题了。内部类也是类。

类静态块-类静态属性这个跟顺序有关系 如果类静态属性在类静态代码块之前 那么类静态属性先初始化

智能推荐

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
© 2014-2019 ITdaan.com 粤ICP备14056181号  

赞助商广告