标题@单例模式的懒汉实现
废话不多说直接上代码:
package singleton;
public class LazySingleton {
private static LazySingleton instance=null;
private LazySingleton(){}
public static LazySingleton getInstance() {
if(instance==null){
instance=new LazySingleton();
}
return instance;
}
public static void main(String[] args) {
new Thread(()->{System.out.println("线程1:"+LazySingleton.getInstance().hashCode());}).start();
new Thread(()->{System.out.println("线程2:"+LazySingleton.getInstance().hashCode());}).start();
}
}
结果:
线程1773230249
线程2773230249
这样的实现是否有线程安全问题,测试一下:代码如下`public static LazySingleton getInstance() {
if(instance==null){
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
instance=new LazySingleton();
}
return instance;
}`
结果:
线程1:1564747649
线程2:1227684418
果然,出现了多个实例,如何解决。将静态方法添加同步锁。
public static LazySingleton getInstance() { if(instance==null){ try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (LazySingleton.class) { if(instance==null){ instance=new LazySingleton(); } } } return instance; }
经过多次测试,结果都是一致的,那么这样的懒汉单例实现就算完成了。
结果:
线程2:1798502179
线程1:1798502179
但是看结果,线程2比线程1先打印出来,没有按照代码顺序打印,似乎与我们预计的结果不一致,这个是因为,jvm进行了指令重排序导致,怎么破,上代码。
private volatile static LazySingleton instance=null;
加入volatile,指令就不会重新排序了。出现的结果就会和我们预计的一致,
结果:
线程1:219756151
线程2:219756151
那么此时,单例模式是否就会如你期望的那样就可以保证一定是单例了呢:
都知道创建对象的几种方式:
1,new 一个对象
2,通过反射创建对象
3,通过clone创建对象
4,通过反序列化实现
5,…
package singleton;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class LazySingleton implements Cloneable,Serializable{
/**
* @Fields serialVersionUID : TODO(用一句话描述这个变量表示什么)
*/
private static final long serialVersionUID = 1L;
private volatile static LazySingleton instance=null;
private LazySingleton(){
}
public static LazySingleton getInstance() {
if(instance==null){
// try {
// Thread.sleep(200);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
synchronized (LazySingleton.class) {
if(instance==null){
instance=new LazySingleton();
}
}
}
return instance;
}
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException, ClassNotFoundException, CloneNotSupportedException {
// new Thread(()->{System.out.println("线程1:"+LazySingleton.getInstance().hashCode());}).start();
// new Thread(()->{System.out.println("线程2:"+LazySingleton.getInstance().hashCode());}).start();
LazySingleton instance1=LazySingleton.getInstance();
System.out.println("instance1:"+instance1.hashCode());
//反射方式获取对象
Constructor<LazySingleton> declaredconstructor=LazySingleton.class.getDeclaredConstructor();
declaredconstructor.setAccessible(true);
LazySingleton instance2=declaredconstructor.newInstance();
System.out.println("instance2:"+instance2.hashCode());
//通过反序列话获取单例
ByteArrayOutputStream bos=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(bos);
oos.writeObject(instance1);
ByteArrayInputStream bis=new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois=new ObjectInputStream(bis);
LazySingleton instance3=(LazySingleton)ois.readObject();
System.out.println("instance3:"+instance3.hashCode());
//通过克隆获取对象
LazySingleton instance4=(LazySingleton) instance1.clone();
System.out.println("instance4:"+instance4.hashCode());
}
}
结果:
instance1:366712642
instance2:1829164700
instance3:1442407170
instance4:1028566121
果然,这样的单例设计还是有被攻击的可能性的。
package singleton;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class LazySingleton implements Cloneable,Serializable{
/**
* @Fields serialVersionUID : TODO(用一句话描述这个变量表示什么)
*/
private static final long serialVersionUID = 1L;
private volatile static LazySingleton instance=null;
//避免反射产生新的单例
private LazySingleton(){
if(instance!=null){
throw new RuntimeException("单例已经实例化了,不能再实例化对象了");
}
}
public static LazySingleton getInstance() {
if(instance==null){
// try {
// Thread.sleep(200);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
synchronized (LazySingleton.class) {
if(instance==null){
instance=new LazySingleton();
}
}
}
return instance;
}
//避免克隆产生多个实例。
@Override
public LazySingleton clone(){
return instance;
}
//避免反序列化导致产生多个实例
private Object readResolve(){
return instance;
}
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException, ClassNotFoundException, CloneNotSupportedException {
// new Thread(()->{System.out.println("线程1:"+LazySingleton.getInstance().hashCode());}).start();
// new Thread(()->{System.out.println("线程2:"+LazySingleton.getInstance().hashCode());}).start();
LazySingleton instance1=LazySingleton.getInstance();
System.out.println("instance1:"+instance1.hashCode());
//通过反序列话获取单例
ByteArrayOutputStream bos=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(bos);
oos.writeObject(instance1);
ByteArrayInputStream bis=new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois=new ObjectInputStream(bis);
LazySingleton instance3=(LazySingleton)ois.readObject();
System.out.println("instance3:"+instance3.hashCode());
//通过克隆获取对象
LazySingleton instance4=(LazySingleton) instance1.clone();
System.out.println("instance4:"+instance4.hashCode());
//反射方式获取对象
Constructor<LazySingleton> declaredconstructor=LazySingleton.class.getDeclaredConstructor();
declaredconstructor.setAccessible(true);
LazySingleton instance2=declaredconstructor.newInstance();
System.out.println("instance2:"+instance2.hashCode());
}
}
结果:
instance1:366712642
instance3:366712642
instance4:366712642
Exception in thread “main” java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:408)
at singleton.LazySingleton.main(LazySingleton.java:74)
Caused by: java.lang.RuntimeException: 单例已经实例化了,不能再实例化对象了
at singleton.LazySingleton.(LazySingleton.java:23)
… 5 more
通过上面的实现,就能避免单例模式被破坏了。