java单例,真的单吗?

说起单例肯定会想起,懒汉,饿汉。但是那都不是完美的。
但是还是要说一下的。
首先Singleton 指的就是被实例化一次的类。在spring ioc 容器中初始化bean的时候默认就是单例的。

饿汉
在程序加载的时候开销比较大,如果没有用到很浪费资源

public class ESingleTon(){
	private static final ESingleTon instance=new ESingleTon();
	private ESingleTon (){}
	public static ESingleTon getInstance(){
		return instance;
	}
}

懒汉

public class LSingleTon(){
	private static LSingleTon instance=null;
	private LSingleTon(){}
	public  static LSingleTon getInstance(){
		if(instance!=null){
		return instance;
	}
//这里为什么要加锁,因为在多线程情况下由于上面的判断不是原子性的所以会产生都是null 的判断。为什么不在方法上加内置锁呢。因为 getInstance()会被多次调用,每次都进入锁其他的线程会被阻塞。所以性能不好。
	synchronized(LSingleTon.class){
		if(instance!=null){
			return instance;
		}
		instance = new LSingleTon();
		return instance;
	}	
}

-------------------------------------------------这是华丽的分割线-------------------------------------------------------
上面是是常用的单例的实现方法,但是为什么说不完美呢。其实在一些情况下并不能保证单例。(序列化,反射)

首先说序列化

 @Test
    public void testLSingleTon() throws IOException, ClassNotFoundException {
        LSingleTon singleTon=LSingleTon.getInstance();
        ObjectOutputStream outputStream=new ObjectOutputStream(new FileOutputStream("E:/test/test.class"));
        outputStream.writeObject(singleTon);
        System.out.println("new: "+singleTon.toString());
        ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream("E:/test/test.class"));
        System.out.println("objinput: "+objectInputStream.readObject().toString());
    }
class LSingleTon implements Serializable{
    private static final long serialVersionUID = 1L;
    private static transient LSingleTon instance=null;

    private Object readResolve(){
        return instance;
    }

    private LSingleTon(){
        System.out.println("constructor: "+this);
    }
    public static LSingleTon getInstance(){
        if(instance!=null){
            return instance;
        }
//这里为什么要加锁,因为在多线程情况下由于上面的判断不是原子性的所以会产生都是null 的判断。为什么不在方法上加内置锁呢。因为 getInstance()会被多次调用,每次都进入锁其他的线程会被阻塞。所以性能不好。
        synchronized(LSingleTon.class){
            if(instance!=null){
                return instance;
            }
            instance = new LSingleTon();
            return instance;
        }
    }
}

在这里插入图片描述

可以看到 下面两个对象地址是不一样 的。所以单利失败。
那怎么办呢
序列化的类中有一个方法被我注释,只要打开就可以了。
只要序列化和反序列化公用一个jvm 堆栈,那么就可以取到相同的对象。
在这里插入图片描述
这样就OK了。

反射破环单例
这个很好理解,只要调用newInstance()就可以常见新的对象。这怎么办?
先看一下newinstance()的源码

在这里插入图片描述
这里判断是不是enum 如果是 不能创建enum objects ,反射是无法newInstance()来创建枚举对象的。

那只要是枚举就行了吗。NO
一个枚举类型的类 编译器 编译以后就是一个 class extends Enum{}
可以看到有一个 静态代码块
用来创建这个类的对象的,而且是根据有多少个enum元素就创建多少个对象对象的引用变量就是enum 中定义的元素名。
所以不能有多个enum 元素,只能有一个 就是一个单例子。

像这样 就OK了
public enum LSingleTon{
instance;

…类的其他属性
}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java 单例模式本身并不一定是线程安全的,需要在实现时考虑线程安全性。 单例模式是一种常用的设计模式,它可以保证一个类只有一个实例,并提供一个全局访问点。在多线程环境下,如果不考虑线程安全性,可能会导致多个线程同时创建多个实例,破坏了单例模式的特性。 常见的单例模式实现方式有懒汉式和饿汉式。 1. 懒汉式 懒汉式是指在第一次使用时才会创建单例实例。在多线程环境下,如果多个线程同时调用 getInstance() 方法,可能会创建多个实例,破坏了单例模式的特性。为了保证线程安全,可以使用 synchronized 关键字或者双重检查锁定来实现。 使用 synchronized 关键字: ```java public class Singleton { private static Singleton instance; private Singleton() {} public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } ``` 使用双重检查锁定: ```java public class Singleton { private static volatile Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } } ``` 2. 饿汉式 饿汉式是指在类加载时就创建单例实例。在多线程环境下,由于实例是在类加载时创建的,因此不会出现多个实例的情况,是线程安全的。 ```java public class Singleton { private static Singleton instance = new Singleton(); private Singleton() {} public static Singleton getInstance() { return instance; } } ``` 需要注意的是,饿汉式在类加载时就创建了实例,可能会浪费一些内存空间,因此需要根据实际情况进行选择。 总之,Java 单例模式本身并不一定是线程安全的,需要在实现时考虑线程安全性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值