spring创建的对象时当线程,当多线程时产生安全问题?

1.spring默认的作用域

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

 

 

 

 

 

2.解释一波单例模式

   饿汉式,懒汉式(不安全,使用的时候再创建)

单例模式是一种对象创建型模式,使用单例模式,可以保证为一个类只生成唯一的实例对象。也就是说,在整个程序空间中,该类只存在一个实例对象。其实,GoF对单例模式的定义是:保证一个类、只有一个实例存在,同时提供能对该实例加以访问的全局访问方法。
最好创建的时候加上valatile防止指令重排序
public static Person4 getnewInstance() {
        if(person ==null){//提高效率
            synchronized (Person.class) {
                if(person == null)
                person = new Person4();
            }
        }
        return person;
    }

3.spring创建单例的模式

在spring的框架里,对象是交给spring容器创建的,spring的创建单例的方式既不是懒汉式也不是饿汉式,是单例注册表模式实现单例模式的

https://blog.csdn.net/u012794505/article/details/80926823

4.spring中创建单线程在多线程中的安全问题

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

2.其实spring的源码里比如RequestContextHolder、TransactionSynchronizationManager、LoxaleContextHolder等这些对象创建方式也是单例,底层就是用ThreadLocal处理的。ThreadLocal基本实现思路是:它会为每个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突,因为每个线程都拥有自己的变量副本,从而也就没必要对该变量进行同步啦。

 5.多例 scope("prototype") 的时候位置不同,那么他被初始化和使用的时候也不一样

   
   1  使用在controller层的情况下,他是在每次请求到该controller的时候,进行一个实例化,就是创建一个新的controller对象

 @PostConstruct
     public void init(){
        //此处每次有新的请求进来的时候,都会实例化一个新的controller对象
        System.out.println("ProductListController-->init:,this:"+this);
     }

   2  server层使用多例的注解,这个地方会出现很多的坑,这个也是我们需要特别注意的
  

  首先我们说在默认的单例情况下
    2.1  在controller层 使用@Autowired 来注入一个server层的实例
    2.1  此时spring容器为我们怎么处理的?
       2.1.1  在创建了一个server单实例后,在引入了该controller的地方,setter到该server的属性上
         此时如果有3个或者n个controller同时 @Autowired Server 该server,那么这n个controller同时拥有同一个server对象
此时我们说下多例模式下
   1  controller层是单例
      server层使用多例模式
我们会发现,在三个controller层注入的server的实例是不一样的。也就是体现了多例

  但是我们需要注意:server的多例是相对于每个不同引入的地方而言的
      其实我们会发现,在spring容器初始化的时候,他会为每一个controller中的server实例化一个对象,这个实例化对象,就被绑定到了这个controller上了,意思就是(如      论你有n多个请求,都请求到同一个controller上,此时这n个请求使用的server对象是同一个。),但是在不同的controller里的server是不一样的。
      同理,如果我们的controller是prototype多例的,server也是多例的,这时候的情况和上面也是类似的controller多例 是在每次请求的时候创建一个新的实例,
    但是server不一样,如果在controller里面,使用@Autowired server进行了注入,该server的实例并不会在每次请求到该位置的时候才进行实例化的,仍然是在spring容      器初始化的时候就一样完成了对每个controller的注入

6.解决

  很多时候我们会在service中定义私有属性,这些属性会被作为该类的全局变量来使用,而且该属性是一个动态赋值, 如果向上面那样,虽然server在被多例后,在不同的controller类下具有不同的实例,但是,对于同一个controller类而言,他们持有同一个server对象,也就是该属性是共享的,随时可能被另外的请求给修改。这时候我们的server中的该属性是非线程安全的。

  所以我们要想办法,在每次请求的时候,都要获取一个新的server实例,这样才可以保证变量线程安全

    @Autowired
    ApplicationContent applicationContent;
    我们可以通过上下文容器在需要的时候主动去获取,
    Server ser = applicationContent.getBean(Server.class);

https://gitee.com/Sxuxiaoyu/noteImages/raw/master/img/spring中的多例.png





posted @ 2020-05-28 10:33  这都没什么  阅读(1180)  评论(0编辑  收藏  举报