zoukankan      html  css  js  c++  java
  • 单例设计模式与类加载顺序详解

    单例设计模式几种实现 (测试所用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

    说明:

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

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

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

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

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

  • 相关阅读:
    02SpringMvc_springmvc快速入门小案例(XML版本)
    01SpringMvc_初识工作流程
    07JavaIO详解_字符流
    06JavaIO详解_IO流中的设计模式-装饰者模式
    05JavaIO详解_仿照IO源码自己去实现一个IO流(为了加深印象,本身没有价值)
    作为程序员,我到底在恐慌什么
    android:layout_weight详解
    Android 遍历界面控件
    一个Activity中使用两个layout实例
    Android获取文件的MD5值
  • 原文地址:https://www.cnblogs.com/yang--yang/p/4856957.html
Copyright © 2011-2022 走看看