一、可见性
直接感受下吧!直接上代码。
@Controller
@RequestMapping("/factory")
public class MachineFactoryController {
// 静态变量位于堆内存中,所有线程共享
private static int i = 0;
@RequestMapping("/access")
@ResponseBody
public Long access(@RequestParam(name = "provinceId") Long provinceId, @RequestParam(name = "cityId") Long cityId) {
int loopCount = 10;
for (int j = 0; j < loopCount; j++) {
// 模拟其他业务
}
i = i + 1;
int step = 10;
if (i % step == 0) {
LOGGER.info("{}", i);
}
return cityId;
}
@RequestMapping("/monitor")
@ResponseBody
public Integer monitor() {
LOGGER.info("{}", i);
return Integer.valueOf(i);
}
}
第一步,启动jmeter开启一个线程组,共有100个线程。使用这个线程组发起100次/factory/access请求,理论上,只要这100个线程执行完毕,i的最终结果是100。但实际上,并不是。
第二步,使用谷歌浏览器直接访问/factory/monitor,打印堆内存中变量i的值,神奇的事情发生了,可以发现是98,这是问什么?
第三步,思考造成i最终结果不正确的原因是什么?
多线程环境下,每个线程同时访问共享资源时,一定存在线程可见性问题。
第四步,如何解决可见性问题?
其实,就此场景而言,使用volatile虽然解决了可见行问题,但是解决不了非原子操作的问题。有两种解决方案。
a、对共享资源加锁,比如说synchronize。
b、使用线程安全的类型,比如说AtomicInteger类。