单例的设计模式中,一些代码的写法会存在线程安全的问题,举例如下:
(1)单例模式的懒汉式[线程不安全,不可用]
public class Singleton { private static Singleton instance=null; private Singleton() {}; public static Singleton getInstance(){ if(instance==null){ instance=new Singleton(); } return instance; } }
这种方式是在调用getInstance方法的时候才创建对象的,所以它就被称为懒汉模式。
这是存在线程安全问题的,那具体是存在怎样的线程安全问题?怎样导致这种问题的?好,我们来说一下什么情况下这种写法会有问题。在运行过程中可能存在这么一种情况:多个线程去调用getInstance方法来获取Singleton的实例,那么就有可能发生这样一种情况,当第一个线程在执行if(instance==null)时,此时instance是为null的进入语句。在还没有执行instance=new Singleton()时(此时instance是为null的)第二个线程也进入了if(instance==null)这个语句,因为之前进入这个语句的线程中还没有执行instance=new Singleton(),所以它会执行instance = new Singleton()来实例化Singleton对象,因为第二个线程也进入了if语句所以它会实例化Singleton对象。这样就导致了实例化了两个Singleton对象。所以单例模式的懒汉式是存在线程安全的,既然它存在问题,那么可能有解决办法,于是就有下面加锁这种写法。
(2)懒汉式线程安全的[线程安全,效率低不推荐使用]
public class Singleton { private static Singleton instance=null; private Singleton() {}; public static synchronized Singleton getInstance(){ if(instance==null){ instance=new Singleton(); } return instance; } }
缺点:效率太低了,每个线程在想获得类的实例的时候,执行getInstance()方法都要进行同步。而其实这个方法只执行一次实例化代码就够了,后面想获得该实例,直接return就行了。方法进行同步效率太低要改进。
(3)单例模式懒汉式[线程不安全,不可用]
public class Singleton7 { private static Singleton instance=null; public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { instance = new Singleton(); } } return instance; } }
这种写法也是不安全的,当一个线程还没有实例化Singleton时另一个线程执行到if(instance == null)这个判断时语句机会进入if语句,虽然加了锁,但是等到第一个线程执行完instance=new Singleton()跳出这个锁时,另一个进入if语句的线程同样会实例化另外一个SIngleton对象。因为这种改进方法不可行。
(4)单例模式懒汉式[线程安全,可用]
public class Singleton7 { private static Singleton instance=null; public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
(5)单例模式饿汉式[线程安全,可用]
public class Singleton1 { private Singleton1() {} private static final Singleton1 single = new Singleton1(); //静态工厂方法 public static Singleton1 getInstance() { return single; } }
饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的。
(6)单例模式的成员变量[线程不安全,不可用]
public class Singleton { int i =0; private Singleton() {} private static final Singleton1 single = new Singleton1(); //静态工厂方法 public static Singleton1 getInstance() { i++; return single; } }
这种写法也是不安全的,当一个线程还没有执行到i++时另一个线程执行到int i=0,导致i=1而不是2,应改为局部变量写法较好
总结:
以上就是单例模式中,会引发的线程安全问题了