遇到标题中的场景时我该怎么设计呢,假如就是标题中 有2个坑位A和B ,2个坑位之间同一个时间点互相抢,抢完修改2个坑位对象属性,但又担心第三者来抢 这2个坑位,所以2个坑位都要加锁,但是如果2个坑位加锁,假如 是A去抢B,A锁住了,B也锁住了,那在A中拿B时 和 B中拿A那就坑位死锁了,还有就是 抢是通过战斗来抢的,而且 A和B最终 还是要依据战的结果 来修改各自的一些属性的,也就是战斗必须要放在锁块里,但战斗逻辑太大,容易照成锁释放 比较慢,那其他线程等待时间就比较长,肯定不行,那该怎么设计呢?
在 A 和 B 里分别加 AutomicInteger 对象作为 一个状态属性,抢夺时通过 该对象的compareAndSet(1, 2) 方法 分别将初始值1 改为2,因为 automicInteger 是原子级的,即是线程安全的对象,那就不用担心多线程,A和B改成功了就表明A和B可以用来抢夺,就算其他多线程来,同一个时间点只能由一个能改变这个A或者B里的这个状态值,上边方法意思是如果原值是第一个参数,那就把值改为第二个参数,成功返回true否则false,也就是说当 一个抢夺 请求过来,把第一个参数1 看为 闲置状态,第二个状态2为战斗状态,首先进行2个坑位的各自状态对象赋值,当能将A和B的状态都能从1 改为2时表明本次战斗 合法,可以打,这个时候如果其他多线程来打A 或者B 时由于A或B已经是战斗状态了,所以这些请求都将不合法,也就不能再向下执行,就不可能在战斗,也不会在战斗完修改A和B的属性值了,也就是只能有一开始那个合法的抢夺请求才能按照代码顺序执行下去,即首先战斗,然后根据结果 来修改A和B的属性值,改完后 再把A和B的那个状态属性对象 automicInteger 值改为1即可(直接用AutomicInteger的set(int x)方法即可),当然这这个重置还原状态的逻辑肯定是放在整个请求操作完全成功后,方法的最后边写的,这样就不会这个请求执行一半就还原的话,那这个请求操作还没完全完成别的线程还是可以来改这个共享的vo属性的。等还原了,其他多线程请求抢夺请求时才能顺利执行下去。这样设计就不涉及 同步锁synchronize,更不会涉及 锁块了代码太多的问题了。