Java 单例模式

一.延迟加载/懒汉式

1.这样单线程下没有问题

2.多线程会有问题

测试案例如下:

线程代码:

public class MyThread implements Runnable {

public MyThread(){}

public void run() {

        System.out.println(" 实例化单例模式 hashcode="+Singleto.getInstance().hashCode());

    }

}

//主测试类public static void main(String[] args){

MyThread myThread = new MyThread();

        for(int i = 0 ;i<9999;i++){

new Thread(myThread).start();

        }

}

执行结果:

对象为NULL,需要创建对象

对象为NULL,需要创建对象

实例化单例模式 hashcode=296019392

对象为NULL,需要创建对象

实例化单例模式 hashcode=1625794892

对象为NULL,需要创建对象

实例化单例模式 hashcode=413818485

对象为NULL,需要创建对象

实例化单例模式 hashcode=450232869

对象为NULL,需要创建对象

实例化单例模式 hashcode=93499693

对象为NULL,需要创建对象

3.解决办法

第一种方案,

最常见的,加synchronized,而synchronized可以加到不同的位置 (方法锁)

 public static synchronized Singleto getInstance(){

        if(instance == null){

                System.out.println("对象为NULL,需要创建对象");

instance = new Singleto();

        }

return instance;

}

效率过于低下,整个方法都被锁住

第二种方法:

public static Singleto getInstance(){

    try{

            synchronized(Singleto.class){

                if(instance == null){

                        System.out.println("对象为NULL,需要创建对象");

instance = new Singleto();

                 }

            }

    }catch (Exception e){

            e.printStackTrace();

     }

return instance;

}

 所有代码都被锁住,应该只需要锁住关键代码就好

第三种方法 DCL双检查机制


public static Singleto getInstance(){

        try{

                if(instance == null){

                        synchronized(Singleto.class){

                                if(instance == null){

System.

out.println("对象为NULL,需要创建对象");

instance = new Singleto();

}

}

}

        }catch (Exception e){

                e.printStackTrace();

         }

return instance;

}

二、

使用内置静态类实现单例

代码如下:

public class SingletoV2 {

private static class Handler {

private static final SingletoV2 LAZY = new SingletoV2();

    }

public static SingletoV2 getInstance(){

return Handler.LAZY;

    }

}

通过上面的实现,可以解决多线程问题。

序列化问题?内置静态类可以达到线程安全的问题,但如果遇到序列化对象时,使用默认方式得到的结果还是多例的

改造如下:public class SingletoV3 implements Serializable {

private static class Handler {

private static final SingletoV3 LAZY = new SingletoV3();

        }

public static SingletoV3 getInstance(){

return Handler.LAZY;

        }

//反序列化的时候就能得到是同一个对象

protected SingletoV3 readResolve() {

return Handler.LAZY;

}

} 

注意必须加上上面的readResolve方法,反序列化的时候才可以得到相同的bean.

如果是反射呢? 反射的时候上面的写法还是有点问题。所以为了解决反射问题修改如下:

public class SingletoV4 implements Serializable {

private static boolean initlized=false;

public SingletoV4(){

//完美解决反射破坏单例,只会执行一次

                synchronized(SingletoV4.Handler.class){

                        if(initlized==false){

initlized = !initlized;

}

else{

throw new RuntimeException("运行时异常,禁止...");

}

}

        }

private static class Handler {

private static final SingletoV4 LAZY = new SingletoV4();

        }

public static SingletoV4 getInstance(){

return Handler.LAZY;

        }

//反序列化的时候就能得到是同一个对象

protected SingletoV4 readResolve() {

return Handler.LAZY;

        }

你可能感兴趣的:(Java 单例模式)