Java单例模式的写法

    xiaoxiao2023-03-24  3

    第一种写法: 懒汉式单例


    class Singleton{ private static Singleton singleleton=null; pulic static Singleton getInstance(){ if(singleleton==null){ singleleton=new Singleton() } return singleleton; } private Singleton(){ singleleton=new Singleton(); } }

    特点:这种写法是线程不安全的,他无法保证同时不被多个线程访问,适合在单线程环境下使用。

    要想保证线程安全,可以参考下面三种写法:

    1)使用synchronized关键字


    class Singleton{ private static Singleton singleleton=null; pulic static synchronized Singleton getInstance(){ if(singleleton==null){ singleleton=new Singleton() } return singleleton; } private Singleton(){ singleleton=new Singleton(); } }

    特点:相比上个方法,在静态方法前多加了个synchronized关键字,使同一时间只能有一个线程访问该代码块。

    2)双重检查锁定


    class Singleton{ private static Singleton singleleton=null; pulic static Singleton getInstance(){ if(singleleton==null){ synchronized(Singleton.class){ if(singleleton==null){ singleleton=new Singleton(); } } } return singleleton; } private Singleton(){ singleleton=new Singleton(); } }

    特点:经过两次判定,第一次检测到实例为空时,增加同步,同步后再次检测到实例为空时,才创建对象实例。有效防止了在多线程环境下创建多个实例的问题。

    3)静态内部类实现


    class Singleton{ private singleton(){} private static class SingleBuilder{ private static Singleton singleton=new Singleton(); //就像private int int=1 } public static Singleton getInstance(){ return SingleBuilder.singleton; } }

    特点:Java中静态内部类可以访问其外部类的成员属性和方法,同时java规定静态内部类只在首次调用时被加载,因此实现了懒汉式,所以他只被加载一次,所以是线程安全的


    2.饿汉式:


    class Singleton{ private static Singleton singleleton=new Singleton(); pulic static Singleton getInstance(){ return singleleton; } private Singleton(){} }

    特点:饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的。


    3.登记式:


    public class Singleton { private static Map< String,Singleton> map = new HashMap< String,Singleton>(); static{ Singleton single = new Singleton(); map.put(single.getClass().getName(), single); } //保护的默认构造子 protected Singleton(){} //静态工厂方法,返还此类惟一的实例 public static Singleton getInstance(String name) { if(name == null) { name = Singleton.class.getName(); System.out.println("name == null"+"--->name="+name); } if(map.get(name) == null) { try { map.put(name, (Singleton) Class.forName(name).newInstance()); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } return map.get(name); } public static void main(String[] args) { Singleton3 single = Singleton.getInstance(null); } }

    登记式单例实际上维护了一组单例类的实例,将这些实例存放在一个Map(登记薄)中,对于已经登记过的实例,则从Map直接返回,对于没有登记的,则先登记,然后返回。 内部实现还是用的饿汉式单例。

    4.使用volatile 关键字


    class Singleton{ private static volatile Singleton Instance=null; public Singleton() { } public static Singleton getInstance(){ if(Instance==null){ synchronized (Singleton.class) { if (Instance == null) { Instance = new Singleton(); } } } return Instance; } }

    volatile 保证在实例对象创建后快速通知其他线程该对象的实例已经存在,不需要重复创建了。

    转载请注明原文地址: https://ju.6miu.com/read-1201766.html
    最新回复(0)