单例模式与多线程

1.立即加载/"饿汉模式"
什么是立即加载?立即加载就是使用类的时候已经将对象创建完毕,常见的实现办法就是直接new实例化.而立即加载从中文的语境来看,有"着急"/"急迫"的含义,所以也称为"饿汉模式".
/*
 * 立即加载方式===饿汉模式
 */
public class SingleObject {
    private static SingleObject single = new SingleObject();
 
    private SingleObject() { }
    
    public static SingleObject getInstance() {
        return single;
    }
    
    
    public static void main(String[] args) {
        new Thread(() -> {
            System.out.println(SingleObject.getInstance().hashCode());
        }).start();
        
        new Thread(() -> {
            System.out.println(SingleObject.getInstance().hashCode());
        }).start();
        
        new Thread(() -> {
            System.out.println(SingleObject.getInstance().hashCode());
        }).start();
    }
} 

hashCode是同一值,说明对象是同一个,也就是实现了立即加载型单例模式.
 
2.延迟加载/"懒汉模式"----在多线程下很容易出现问题
什么是延迟加载?延迟加载就是在调用get()方法时实例才被创建,常见的实现办法就是在get()方法中进行new实例化.而延迟加载从中文的语境来看,是"缓慢"/"不急迫"的含义,所以也称为"懒汉模式".
 
解决不同步的办法
/*
 * 延迟加载----懒汉模式
 * 在多线程下的解决办法,使用DCL双检查锁机制
 * 效率比较高
 */
public class SingleObject1 {
    private static SingleObject1 single;
    private SingleObject1() {
    }
    public static SingleObject1 getInstance() {
        if (single == null) {
            synchronized (SingleObject1.class) {
                if (single == null) {
                    single = new SingleObject1();
                }
            }
        }
        return single;
    }
    public static void main(String[] args) {
        new Thread(() -> System.out.println(SingleObject1.getInstance()
                .hashCode())).start();
        new Thread(() -> System.out.println(SingleObject1.getInstance()
                .hashCode())).start();
        new Thread(() -> System.out.println(SingleObject1.getInstance()
                .hashCode())).start();
    }
}

使用双重检查锁功能,成功地解决了"懒汉模式"遇到多线程的问题.DCL也还是大多数多线程结合单例模式使用的解决办法.

 

3.使用静态内部类实现单例模式

/*
 * 通过静态内部类实现单例模式
 */
public class SingleObject2 {
    private static class SingleHandler {
        private static SingleObject2 single = new SingleObject2();
    }
    
    private SingleObject2() { }
    
    public static SingleObject2 getInstance() {
        return SingleObject2.SingleHandler.single;
    }
    
    
    public static void main(String[] args) {
        new Thread(() -> System.out.println(SingleObject2.getInstance().hashCode())).start();
        new Thread(() -> System.out.println(SingleObject2.getInstance().hashCode())).start();
        new Thread(() -> System.out.println(SingleObject2.getInstance().hashCode())).start();
        new Thread(() -> System.out.println(SingleObject2.getInstance().hashCode())).start();
    }
}
 
4.序列化与反序列化实现单例模式
静态内部类可以达到线程安全问题,但如果遇到序列化对象时,使用默认的方式运行得到的结果还是多例的.
解决办法就是反序列化中使用readResolve()方法.

 
5.使用static代码块实现单例模式
静态代码块中的代码在使用类的时候就已经执行了,所以可以应用静态代码块的这个特性来实现单例设计模式.
/*
 * 使用静态代码块实现单例模式
 */
public class SingleObject3 {
    private static SingleObject3 single;
    
    public SingleObject3() { }
    
    static {
        single = new SingleObject3();
    }
    
    public static SingleObject3 getInstance() {
        return single;
    }
    
    public static void main(String[] args) {
        new Thread(() -> { 
            for(int i = 0 ; i < 5; i++) {
                System.out.println(SingleObject3.getInstance().hashCode());
            }
        }).start();
        new Thread(() -> { 
            for(int i = 0 ; i < 5; i++) {
                System.out.println(SingleObject3.getInstance().hashCode());
            }
        }).start();
    }
}
 
6.使用enum枚举数据类型实现单例模式
枚举enum和静态代码块的特性相似,在使用枚举类是,构造方法会被自动调用,也可以应用其这个特性实现单例模式.
上面将枚举类暴露出来了,下面进行完善.
 
 
posted @ 2018-04-02 16:30  做个安分守己的陈某某  阅读(276)  评论(0)    收藏  举报