SpringMVC,这个大家每天都在使用的框架,不知大家在使用的时候,是否有考虑过它线程安全的问题呢?

我们都知道,SpringMVC通过前端控制器DispatcherServlet来分发处理请求,通过对请求URL和@RequestMapping的映射关系,来调用Controller中对应的方法。

Spring的IOC容器中,默认都是单例的,Controller也不例外。

服务器肯定是需要接收大量请求的,对于多个请求肯定是开启多个线程去并发执行的,否则单线程排队吞吐量就太低了

多线程并发执行,Controller又是单例,那么必定会存在多线程安全问题

前言

要讨论接下来的问题,首先需要了解一下JVM的内存模型,知道哪些内存是线程共享的、哪些是线程私有的。

image

例子

多线程安全无非就是数据共享一致性的问题,对于一个简单的i++操作,下面给出两个例子。

不安全的

public class Demo {
	private int i = 0;

	void add(){
	    i++;
		System.out.println(i);
	}
}

首先i是一个全局变量,和Demo实例一起保存在堆内存中,是线程共享的。

而且i++本身不是一个原子操作,线程在执行每一条JVM指令前都有可能失去CPU的执行权,多个线程去对i进行计算和赋值,最终输出结果将不可预测,出现重复值。

Tips:关于“i++不是原子操作”可以查看笔者的博客:《为什么说i++不是原子操作》

安全的

public class Demo {

	void add(){
		int i = 0;
		i++;
		System.out.println(i);
	}
}

现在i是一个局部变量了,保存在线程私有的栈内存中。

每开启一个线程,JVM就会分配一个线程私有的栈空间,方法的执行就是一个个栈帧入栈和出栈的过程。

每个线程的add()入栈时,都会在局部变量表中保存了一个i变量,每个线程操作的都是内部i,也就不存在数据安全问题了。

SpringMVC

在使用SpringMVC时,程序员多少还是需要考虑一下多线程下的数据安全问题。

一般来说,避免去修改Service和Dao,不去对全局变量进行修改,就不会出现数据不一致问题。

局部变量使用起来简单,但是会使得对象被频繁的创建和回收,影响性能消耗内存。

全局变量虽然不会被频繁创建和回收,但是要考虑多线程下数据一致性问题,代码编写复杂,要根据应用实际情况作出取舍。

不安全的

@RestController
public class Demo {
	@Autowired
	PersonDao personDao;
	@Autowired
	Person person;

	//线程不安全
	@RequestMapping("/save")
	public void save(String name){
		person.setName(name);
		personDao.insert(person);
	}
}

安全的

@RestController
public class Demo {
	@Autowired
	PersonDao personDao;

	//线程安全
	@RequestMapping("/save")
	public void save(String name){
		Person person = new Person();
		person.setName(name);
		personDao.insert(person);
	}
}

可以使用synchronized关键字,或者利用java.util.concurrent包下的并发工具类来保证数据同步。

测试

@RequestMapping("/test")
public void login_on() {
	System.err.println(Thread.currentThread().getName());
}

开启10个线程去并发请求,输出如下:

http-nio-9001-exec-4
http-nio-9001-exec-1
http-nio-9001-exec-2
http-nio-9001-exec-8
http-nio-9001-exec-7
http-nio-9001-exec-6
http-nio-9001-exec-10
http-nio-9001-exec-3
http-nio-9001-exec-9
http-nio-9001-exec-5

频繁创建线程开销是很大的,SpringMVC肯定用到了线程池,使用池中的10个线程来处理请求,而且是基于非阻塞的NIO。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐