欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring问题 之创建好的单例对象是否存在线程安全问题

程序员文章站 2022-05-23 10:18:52
...

Spring的Bean作用域

作用域 字符 描述
单例 singleton 整个应用中只创建一个实例
原型 prototype 每次注入时都新建一个实例
会话 session 为每个会话创建一个实例
请求 request 为每个请求创建一个实例

默认的是:单例 singleton

创建单例的方式是否线程安全

懒汉式(不安全写法):

public class Singleton{ 
    private Singleton(){}
    private static Singleton singleton = null;  //不建立对象
    public static Singleton getInstance(){
		if(singleton == null) {        //先判断是否为空
			singleton = new Singleton ();  //懒汉式做法 
		}
		return singleton;
     }
}

饿汉式(不存在线程安全问题):

public class Singleton{ 
    public Singleton(){}
    private static Singleton singleton = new Singleton()//建立对象
    public static Singleton getInstance(){
  		return singleton;//直接返回单例对象 }
}

懒汉式(安全写法):

public class Singleton{ 
    private Singleton(){}
    private static Singleton singleton = null;  //不建立对象
    public static synchronized Singleton getInstance(){
             if(singleton == null) {        //先判断是否为空
                 singleton = new Singleton ();  //懒汉式做法 
             }
             return singleton ;
     }
}

怎么判断使用已经创建好的单例对象是否线程安全

  • 看这个单例里有没有全局变量(全局变量就是成员变量,成员变量又分实例变量和静态变量)
  • 如果有全局变量,看它是不是只可以读取而不能写入(有没有发布set方法)

如果满足上面两个条件,那么这个单例就是不安全的。

Spring的单例模式与线程安全

Spring框架里的bean获取实例的时候都是默认单例模式,所以在多线程开发里就有可能会出现线程不安全的问题。当多个用户同时请求一个服务器时,容器(tomcat)会给每一个请求分配一个线程,这时多个线程会并发执行该请求所对应的业务逻辑(controller里的方法),此时就要注意啦,如果controller(是单例对象)里有全局变量并且又是可以修改的,那么就需要考虑线程安全的问题。
解决方案有很多,比如设置@scope(“prototype”)为多例模式,为每个线程创建一个controller,还可以使用ThreadLocal。

ThreadLocal基本实现思路是:它会为每个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突,因为每个线程都拥有自己的变量副本,从而也就没必要对该变量进行同步啦。

在ssh或ssm框架里的service或dao对象虽然也是单例模式,但正如上面分析的,他们没有可修改的全局变量,所以在多线程环境下也是安全的。

有状态对象和无状态对象

无状态对象:无法存储数据,不存在线程安全问题。
有状态对象:有数据存储功能,多线程环境下存在线程安全问题。

其实如果一个有状态对象且没有set方法只是可读,其实也是安全的。

相关标签: # Spring问题