一.延迟加载/懒汉式
1.这样单线程下没有问题
2.多线程会有问题
测试案例如下:
线程代码:
public class MyThread implements Runnable {
public MyThread(){}
public void run() {
System.out.println(" 实例化单例模式 hashcode="+Singleto.getInstance().hashCode());
}
}
//主测试类public static void main(String[] args){
MyThread myThread = new MyThread();
for(int i = 0 ;i<9999;i++){
new Thread(myThread).start();
}
}
执行结果:
对象为NULL,需要创建对象
对象为NULL,需要创建对象
实例化单例模式 hashcode=296019392
对象为NULL,需要创建对象
实例化单例模式 hashcode=1625794892
对象为NULL,需要创建对象
实例化单例模式 hashcode=413818485
对象为NULL,需要创建对象
实例化单例模式 hashcode=450232869
对象为NULL,需要创建对象
实例化单例模式 hashcode=93499693
对象为NULL,需要创建对象
3.解决办法
第一种方案,
最常见的,加synchronized,而synchronized可以加到不同的位置 (方法锁)
public static synchronized Singleto getInstance(){
if(instance == null){
System.out.println("对象为NULL,需要创建对象");
instance = new Singleto();
}
return instance;
}
效率过于低下,整个方法都被锁住
第二种方法:
public static Singleto getInstance(){
try{
synchronized(Singleto.class){
if(instance == null){
System.out.println("对象为NULL,需要创建对象");
instance = new Singleto();
}
}
}catch (Exception e){
e.printStackTrace();
}
return instance;
}
所有代码都被锁住,应该只需要锁住关键代码就好
第三种方法 DCL双检查机制
public static Singleto getInstance(){
try{
if(instance == null){
synchronized(Singleto.class){
if(instance == null){
System.
out.println("对象为NULL,需要创建对象");
instance = new Singleto();
}
}
}
}catch (Exception e){
e.printStackTrace();
}
return instance;
}
二、
使用内置静态类实现单例
代码如下:
public class SingletoV2 {
private static class Handler {
private static final SingletoV2 LAZY = new SingletoV2();
}
public static SingletoV2 getInstance(){
return Handler.LAZY;
}
}
通过上面的实现,可以解决多线程问题。
序列化问题?内置静态类可以达到线程安全的问题,但如果遇到序列化对象时,使用默认方式得到的结果还是多例的
改造如下:public class SingletoV3 implements Serializable {
private static class Handler {
private static final SingletoV3 LAZY = new SingletoV3();
}
public static SingletoV3 getInstance(){
return Handler.LAZY;
}
//反序列化的时候就能得到是同一个对象
protected SingletoV3 readResolve() {
return Handler.LAZY;
}
}
注意必须加上上面的readResolve方法,反序列化的时候才可以得到相同的bean.
如果是反射呢? 反射的时候上面的写法还是有点问题。所以为了解决反射问题修改如下:
public class SingletoV4 implements Serializable {
private static boolean initlized=false;
public SingletoV4(){
//完美解决反射破坏单例,只会执行一次
synchronized(SingletoV4.Handler.class){
if(initlized==false){
initlized = !initlized;
}
else{
throw new RuntimeException("运行时异常,禁止...");
}
}
}
private static class Handler {
private static final SingletoV4 LAZY = new SingletoV4();
}
public static SingletoV4 getInstance(){
return Handler.LAZY;
}
//反序列化的时候就能得到是同一个对象
protected SingletoV4 readResolve() {
return Handler.LAZY;
}
}