单例模式怎么保证线程安全?java写一个线程安全的单例模式

KLQ 2020-08-06 10:38:45 java常见问答 7774

java单例模式如何才能保证线程安全呢?下面要给大家分享的就是线程安全的单例模式代码,一起来详细的了解一下。

1.饿汉式单例,指的就是在方法调用之前,实例就已经创建完成了。

package jichu;
public class Singleton
{
    private static Singleton instance = new Singleton();
    private Singleton()
    {}
    public static Singleton getInstance()
    {
        return instance;
    }
}

注意一下,要保证系统当中不会有人创建多余的实例,所以,就将构造函数设置成为了private,instance对象必须是private并且要是static的,假如不是private的话,那么,instance的安全性将不能够保证,一个很小的意外,很有可能会导致instance变为null。

存在的问题,Singleton实例是在什么时候创建是不收控制的,对于静态成员instance,它会在类第一次初始化时被创建,那么这个时候,并不一定是getInstance方法第一次被调用的时候。

2、加入synchronized的懒汉式单例,指在调用时才会去创建这个实例,为了防止对象被多次创建,使用synchronized进行方法同步。

package jichu;
public class Singleton
{
    private static Singleton instance;
    private Singleton()
    {}
    public static synchronized Singleton getInstance()
    {
        if (instance == null)
        {
            instance = new Singleton();
        }
        return instance;
    }
}

这样充分的利用了延迟加载,只有在真正要创建的时候创建对象,但是,并发环境下加锁,竞争激烈的场合对性能会造成一定的影响。

3、使用静态内部类方式,利用classloder机制来保证初始化instance时只有一个线程。

和饿汉式区别:饿汉式只要Singleton类被加载,instance就会被实例化,这种方式是Singleton类被加载了,instance也不一定被初始化,只有通过调用getInstance()方法的时候,才会显式装载SingletonHolder类,从而实例化instance,能够做到真正需要的时候创建实例。

package jichu;
public class Singleton
{
    private Singleton()
    {}
    //	静态内部类
    private static class SingletonHolder
    {
        private static Singleton instance = new Singleton();
    }
    public static Singleton getInstance()
    {
        return SingletonHolder.instance;
    }
}

4.双重校验锁(不大推荐)。用两个if判断这个对象是否是空的原因,主要是在于,多个线程同时创建对象时,多个线程有可能都停止在第一个if判断的地方,等待锁的释放,然后多个线程都创建了对象,这样就不是单例模式了,所以的话,使用两个if。

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

5.使用static代码块,静态代码块中的代码在使用类的时候就已经执行。

package jichu;
public class Singleton
{
    private static Singleton instance = null;
    private Singleton()
    {}
    static
    {
        instance = new Singleton();
    }
    public static Singleton getInstance()
    {
        return instance;
    }
}

6.使用枚举数据类型。

package jichu;
public class Singleton
{
    private enum MyEnumSingleton
    {
        singletonFactory;
        private Singleton instance;
        //		枚举类的构造方法在类加载时被实例化
        private MyEnumSingleton()
        {
            instance = new Singleton();
        }
        public Singleton getInstance()
        {
            return instance;
        }
    }
    public static Singleton getInstance()
    {
        return MyEnumSingleton.singletonFactory.getInstance();
    }
}

以上的内容就为你介绍到这里了,请继续关注奇Q工具网吧,更多java编程常见问题,可以为你进行分享哦。

推荐阅读:

springmvc单例bean线程安全怎么解决?解决方法分享

线程安全的单例模式有几种?有何特点?

单例模式匿名内部类底层实现