多线程环境下实现单例模式

1.单例模式的两种实现方法

(1) 饿汉式:就是在使用类时就将对象创建完毕
实例:

public class MyObject {
    private static MyObject instance=new MyObject();
    private MyObject(){//私有化构造方法,防止外部创建
    }
    public static MyObject getInstance(){//提供外部访问接口
        return instance;
    }
}
//测试
public static void main(String[] args) {
        MyObject myObject1=MyObject.getInstance();
        MyObject myObject2=MyObject.getInstance();
        System.out.println(myObject1.hashCode());
        System.out.println(myObject2.hashCode());
    }

结果:可见hashcode的值一样的。所有相同对象
在这里插入图片描述
(2) 懒汉式(延迟加载):就是对象在调用getinstance()方法时才被创建
实例:

public class MyObject2 {
    private static MyObject2 instance;
    private MyObject2(){
    }
    public static  MyObject2 getInstance(){
        if(instance==null){
            instance=new MyObject2();
        }
        return instance;
    }
}
//测试
public static void main(String[] args) {
        MyObject2 myObject1=MyObject2.getInstance();
        MyObject2 myObject2=MyObject2.getInstance();
        System.out.println(myObject1.hashCode());
        System.out.println(myObject2.hashCode());
    }

结果:
在这里插入图片描述

2.多线程下单例模式的实现

上面介绍了单线程下单例模式的实现,但是在多线程环境下,懒汉式单例模式会出现问题。
如:

public class MyObject2 {
    private static MyObject2 instance;
    private MyObject2(){
    }
    public static  MyObject2 getInstance(){
            try {
            if(instance==null){
                Thread.sleep(1000);
                instance=new MyObject2();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        return instance;
    }
}
//线程
public class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println(MyObject2.getInstance().hashCode());
    }
}
//测试
 public static void main(String[] args) {
       MyThread thread1=new MyThread();
       MyThread thread2=new MyThread();
       MyThread thread3=new MyThread();
        thread1.start();
        thread2.start();
        thread3.start();
    }

结果:出现了不一样的对象。原因是:当第一个线程进入if时,为null,停了一会,此时第二个线程来了,对象还没有被new出来,此时还是为空。又进入if了,再次调用new所有创建了不同的对象。同理第三个线程也是如此。所有看到了三个不同的对象。
在这里插入图片描述

(1).使用synchronized同步方法

在getinstance()方法上添加同步关键字,其他不变

 synchronized public static  MyObject2 getInstance(){
            try {
             if(instance==null){
                Thread.sleep(1000);
                instance=new MyObject2();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        
        return instance;
    }

结果:但是这种同步的方式,只有当一个线程执行完了,另一个线程才能执行,有点影响性能。
在这里插入图片描述

(2) 使用synchronized同步语句块

更改代码:

public static MyObject3 getInstance(){
            try {
                synchronized (MyObject3.class){
                    if(instance==null) {
                        Thread.sleep(1000);
                        instance = new MyObject3();
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        return instance;
    }

结果:
在这里插入图片描述

(3) 使用双重锁机制

实例:

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

结果:这个方式实现了付出一次同步开销就可以实现单列。
在这里插入图片描述

(4)使用静态内置类

此方式与饿汉式差不多

public class MyObject {
	private static class MyObjecthandler{
		private static MyObject myObject=new MyObject();
	}
	private MyObject(){}
	public static MyObject getInstance(){
		return MyObjecthandler.myObject;
	} 
}

(5)序列化和反序列化的单列模式实现

实例:

public class MyObject implements Serializable{
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private static class MyObjecthandler{
		private static MyObject myObject=new MyObject();
	}
	private MyObject(){}
	public static MyObject getInstance(){
		return MyObjecthandler.myObject;
	} 
	//一定要写这个方法
	protected Object readResolve() throws ObjectStreamException{
		System.out.println("调用了readResolve方法");
		return MyObjecthandler.myObject;
	}
}
//测试
public class Test {
public static void main(String[] args) {
	MyObject myObject=MyObject.getInstance();
	try {
		FileOutputStream foutputStream=new FileOutputStream(new File("my.txt"));
		ObjectOutputStream os=new ObjectOutputStream(foutputStream);
		os.writeObject(myObject);
		os.close();
		foutputStream.close();
		System.out.println(myObject.hashCode());
	} catch (FileNotFoundException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	try {
		FileInputStream fileInputStream=new FileInputStream(new File("my.txt"));
		ObjectInputStream oInputStream=new ObjectInputStream(fileInputStream);
		MyObject object= (MyObject)oInputStream.readObject();
		oInputStream.close();
		fileInputStream.close();
		System.out.println(object.hashCode());
	} catch (FileNotFoundException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	} catch (ClassNotFoundException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	
}
}

结果:
在这里插入图片描述

(6)使用枚举类型实现单例模式

实例:一般推荐使用这种方式。

public class MyObject {
    public enum  MyEnum{
        INSTANCE;//可以把它看做是MyEnum的一个实例
         private MyObject object;
         private MyEnum(){
             object=new MyObject();
        }
    public MyObject getObject(){
             return object;
    }
    }
    public static MyObject getInstance(){
        return MyEnum.INSTANCE.getObject();
    }
}
//线程
public class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println(MyObject.getInstance().hashCode());
    }
}

结果:
在这里插入图片描述

(7) 使用静态代码块实现

实例:更改MyObject4 代码

public class MyObject4 {
    private static MyObject4 instance=null;
    static {
        instance=new MyObject4();
    }
    private MyObject4(){//私有化构造方法,防止外部创建
    }
    public static MyObject4 getInstance(){//提供外部访问接口
        return instance;
    }
}

结果:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值