hjr-MUD游戏(六):多线程锁ThreadLocal和Synchronized

假设 怪物g 有100点血量
勇士a和勇士b 分别有1点攻击力

使用情景

现在两种情况

  1. a与b未组队,我们需要保证a与b对g的攻击后,g的血量变化对两个人是独立的,那么我们对g加锁就要用ThreadLocal
  2. a与b组队,a与b对g攻击后,g的血量对两个人是共享的,那么我们对g加锁就要用Synchronized

拿spring举例,我们都知道spring每个请求会创建一个线程,默认又是单例模式

所以每个用户的请求可以理解为一个线程,

现在我们定义一个全局变量 gHP,怪物g的血量

为什么加锁

由于是gHP全局变量,会存在多线程竞争问题,先说为什么要加锁。

  1. 比如a与b没有组队,a 和 b同时攻击g,a只有1点攻击力,打了g一下,却发现g血量下降的多了一倍(因为b也在攻击g)

我们用ThreadLocal(以空间换时间)修饰gHP变量,那么a与b对g的攻击导致的gHP变化就是独立的
因为gHP会被创建一个副本。a与b单独操作各自的gHP副本。

  1. a与b组队了,我们用Synchronized(以时间换空间)修饰gHP变量,表面上看是没意义的,加不加锁gHP都是共享 的

但是如果我们多了个判断,比如 如果gHP==0 则给打败g的勇士奖励
现在a把g打到0滴血,结果在刚要做上面判断的时候
b也打了g,结果还没判断完,gHp变成-1了,这样就出现bug了。
用Synchronized加锁后,a操作gHP时候b无法操作,就可以避免上面的bug。

使用范围

所以Synchronized 修饰的是一个代码段,该段中有对共享资源的读取判断等操作

ThreadLocal 修饰的是一个共享变量,会为该变量在每个线程创建副本

顺便一提

数据库连接dao,也是全局变量

@Autowired
UserMapeer userMapper;

如果你看数据库日志,会发现为每个用户依旧开启一个新连接

单例的controller中为什么会出现多例的dao

就是因为spring对某些bean 使用了 ThreadLocal 修饰

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章