Java单例模式(6种写法)

Java单例模式

饿汉式

  1. 类初始化时创建对象,不管需不需要实例对象,都会创建
  2. 不存在线程安全问题,因为实例是在类创建和初始化时创建,是由类加载器完成的,类加载器是线程安全的

书写
(1)构造器私有化
(2)自行创建,并且用静态变量保存
(3)向外提供这个实例
(4)强调这是一个静态的,可以使用final修饰

直接方式

// 简洁直观
public class Singleton1 {
    private Singleton1(){}
    public static final Singleton1 INSTANCE = new Singleton1();
}

枚举式

// 最简洁
public enum Singleton2 {
	INSTANCE;
}

静态代码块方式

// 适合复杂的实例化
class A {
    static final String info = "password";
}
public class Singleton3_test {
    public String info;

    private Singleton3(String info) {
        this.info = info;
    }
    static {
        // 从其他地方获取的值
        String val = A.info;
        INSTANCE = new Singleton3_test(val);
    }

    public static final Singleton3_test INSTANCE;

    @Override
    public String toString() {
        return "Singleton3{" +
                "info='" + info + '\'' +
                '}';
    }

    public String getInfo() {
        return info;
    }

    public void setInfo(String info) {
        this.info = info;
    }
}

测试

public class Test1 {
    public static void main(String[] args) {
        System.out.println(Singleton1.INSTANCE);
        System.out.println(Singleton2.INSTANCE.getClass());
        System.out.println(Singleton3.INSTANCE);
    }
}
/* 结果
	Singleton1@1b6d3586
	class Singleton2
	Singleton3{info='password'}
*/

懒汉式

延迟创建实例对象,需要时才去创建对象,否则不创建

书写
(1)构造器私有化
(2)用一个静态变量保存这个唯一的实例
(3)提供一个静态方法,获取这个实例对象

线程不安全(适用于单线程)

public class SingletonLan1 {
    private SingletonLan1(){}
    private static SingletonLan1 instance;
    public static SingletonLan1 getInstance(){
        if (instance == null){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            instance = new SingletonLan1();
        }
        return instance;
    }
}

// 测试
public class Lan_Test1 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {

        Callable<SingletonLan1> call = new Callable<SingletonLan1>() {
            @Override
            public SingletonLan1 call() throws Exception {
                return SingletonLan1.getInstance();
            }
        };

        ExecutorService es = Executors.newFixedThreadPool(2);
        Future<SingletonLan1> f1 = es.submit(call);
        Future<SingletonLan1> f2 = es.submit(call);
        SingletonLan1 s1 = f1.get();
        SingletonLan1 s2 = f2.get();
        es.shutdown();

        System.out.println(s1 == s2);
        System.out.println(s1);
        System.out.println(s2);
    }
}

线程安全(适用于多线程)

public class SingletonLan2 {
    private SingletonLan2(){}
    private static SingletonLan2 instance;
    public static SingletonLan2 getInstance(){
        if (instance == null){
            synchronized (SingletonLan2.class){
                if (instance == null) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    instance = new SingletonLan2();
                }
            }
        }
        return instance;
    }
}

// 测试
public class Lan_Test2 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {

        Callable<SingletonLan2> call = new Callable<SingletonLan2>() {
            @Override
            public SingletonLan2 call() throws Exception {
                return SingletonLan2.getInstance();
            }
        };

        ExecutorService es = Executors.newFixedThreadPool(2);
        Future<SingletonLan2> f1 = es.submit(call);
        Future<SingletonLan2> f2 = es.submit(call);
        SingletonLan2 s1 = f1.get();
        SingletonLan2 s2 = f2.get();
        es.shutdown();

        System.out.println(s1 == s2);
        System.out.println(s1);
        System.out.println(s2);
    }
}

静态内部类方式(适用于多线程)

  1. 在内部类被加载和创建时,才去创建实例对象
  2. 静态内部类不会随着外部类的加载和初始化而初始化,它是要单独加载和初始化的
  3. 因为是内部类创建和初始化时,创建的对象,所以不存在线程安全问题
// 相比上一种方法,简洁许多
public class SingletonLan3 {
    private SingletonLan3(){}

    private static class Inner{
        private static final SingletonLan3 INSTANCE = new SingletonLan3();
    }

    public static SingletonLan3 getInstance(){
        return Inner.INSTANCE;
    }
}
发布了21 篇原创文章 · 获赞 5 · 访问量 2070

猜你喜欢

转载自blog.csdn.net/fan521dan/article/details/95638268