Servlet 默认是单例模式,所以说 Tomcat 只创建一个实例,所以当多个线程同时访问同一个Servlet 的时候,Servlet是线程不安全的
问题
Servlet 线程不安全问题是建立在 Java 多线程的基础之上,它的生命周期是由Servlet容器(即Tomcat)来维护与管理的
当客户端第一次发送请求时,内部的Dispatcher线程来处理和分发Web请求,也就说Dispatcher线程从线程池中选出一个工作组线程,并将请求传递给该线程,并会对请求相对应的Servlet对象执行 init()方法 进行初始化,然后再调用 service() 方法
当客户端发起第二次请求时,则会直接调用 service() 方法,不会再调用 init()方法,因为 servlet对象是单例的
如果客户端发起多次并发请求,可能会导致多个线程同时调用 service() 方法,如果代码中定义了实例变量或静态变量,那么可能就会发生线程不安全的问题,也就是说可能存在多个线程,在同一时间使用同一个变量
解决
- 不在 servlet 中使用成员变量,改为使用局部变量或者使用安全类,比如 java.util.concurrent 下的类,使用原子类 AtomicInteger,能够保证线程安全问题,避免出现数据不一致
- 可以给 servlet 中的方法添加 自动锁synchronized 或者 手动锁Lock,但是也会带来一些不好的就是,在并发请求访问时,会造成线程阻塞等待