有状态Bean和无状态Bean

有状态Bean :有状态就是有数据存储功能。有状态对象(Stateful Bean),就是有实例变量的对象 ,可以保存数据,是非线程安全的。在不同方法调用间不保留任何状态。

无状态就是一次操作,不能保存数据。

无状态Bean :无状态对象(Stateless Bean),就是没有实例变量的对象 。不能保存数据,是不变类,是线程安全的。

无状态的Bean适合用不变模式,技术就是单例模式,这样可以共享实例,提高性能。

Spring中的Bean

Spring 中默认为单例模式 singleton ,单例模式下的无状态Bean 是线程安全的,而 有状态Bean 则是线程非安全的。

如果要使用 有状态Bean 应将 Spring 更改为 prototype 原型模式。

SpingBoot 在组件上使用 @Scope(“prototype”) 注解

而如果是prototype的话,就不会出现资源共享的问题。(即不会出现线程安全的问题)

或者也可将 私有全局变量 更换为 方法的参数变量 或 方法的局部变量

也可以使用 ThreadLocal 的独立线程副本来保证线程安全。

从源头上来说,在Spring中不应使用有状态Bean。

使用 单例模式 singleton 的优势:

  1. 提高性能,不用每次创建Controller实例,减少了对象创建和垃圾收集的时间
  2. 没多例的必要
    由于只有一个Controller的实例,当多个线程同时调用它的时候,它的成员变量就不是线程安全的。
    当然在大多数情况下,我们根本不需要Controller考虑线程安全的问题,除非在类中声明了成员变量。因此Spring MVC的Contrller在编码时,尽量避免使用实例变量。如果一定要使用实例变量,则可以改用以下方式:
  3. Controller中声明 scope=”prototype”,即设置为多例模式
  4. 在Controller中使用ThreadLocal变量,如:private ThreadLocal count = new ThreadLocal();

实体bean不是单例的,并没有交给spring来管理,每次我们都手动的New出来的【如EMakeType et = new EMakeType();】,所以即使是那些处理我们提交数据的业务处理类是被多线程共享的,但是他们处理的数据并不是共享的,数据时每一个线程都有自己的一份,所以在数据这个方面是不会出现线程同步方面的问题的。

  1. 对于实体bean一般通过方法参数的的形式传递(参数是局部变量),所以多线程之间不会有影响。

  2. 有的地方对于有状态的bean直接使用prototype原型模式来进行解决。

  3. 对于使用bean的地方可以通过new的方式来创建

Spring依赖注入static静态变量的方法

@Autowired
private static YourClass yourClass;

不能直接注入

需要将静态变量作为通用组件注入

spring 不允许/不支持把值注入到静态变量中,如:

import org.springframework.beans.factory.annotation.Value;  
import org.springframework.stereotype.Component;

@Component
public class GlobalValue {

@Value("${mongodb.db}")
public static String DATABASE;

}

如果你获取GlobalValue.DATABASE,会得到null
GlobalValue.DATABASE = null
那我们如何解决这个问题呢。
好在spring支持set方法注入,我们可以利用非静态setter 方法注入静态变量。如:

import org.springframework.beans.factory.annotation.Value;  
import org.springframework.stereotype.Component;

@Component
public class GlobalValue {

public static String DATABASE;

@Value("${mongodb.db}")
public void setDatabase(String db) {
DATABASE = db;
}

}

什么情况下使用多线程?

多线程的使用离不开“阻塞”这个概念,不过,我想先对这个概念加以扩充,首先先来回想一下阻塞概念原本的意思,简单的说,就是程序运行到某些函数或过程后等待某些事件发生而暂时停止CPU占用的情况;也就是说,是一种CPU闲等状态,不过有时我们使用多线程并不一定是保持闲等时的程序响应,例如在追求高性能的程序中,某条线程在进行高强度的运算,此时若对运算性能不满意,我们也许会再启动若干条运算线程(当然,是在CPU有运算余力的情况下),此时,高强度运算应该归为一种“忙等”状态。

说到这,多线程归根究底是为了解决”等”的问题,那我们这样定义一个阻塞过程:程序运行该过程所消耗的时间有可能在运行上下文间产生明显的卡顿;这里使用“可能”是因为有些情况下,诸如Socket通信,如果数据源源不断的进入,那么阻塞的时间可能非常小,但我们还是使用了一条线程(nio另说)来处理它,因为我们无法保证数据到来的持续性和有效性;”卡顿”带有主观臆想,也就是说是使用者(人或一些自动化程序)不可接受的。

接下来,对什么时候使用多线程做一个回答:编写程序过程中需要使用某些阻塞过程时,我们才使用多线程,或者更进一步讲,使用多线程的目的是对阻塞过程中的实际阻塞的抽象提取。前半句话应该很好理解,而后面的一句虽然不太好懂,不过它对一个程序应具有的合理线程数量进行了阐释(这点接下来解释)。

一句话总结:

在编写程序时,遇到了阻塞过程而不想使整个程序停止响应时,应使用多线程;一个程序的合理线程数量取决于对实际阻塞的抽象程度。