Java:Java 线程不安全分析,同步锁和Lock机制,哪个解决方案更好


Java:Java 线程不安全分析,同步锁和Lock机制,哪个解决方案更好
文章图片
Java:Java 线程不安全分析,同步锁和Lock机制,哪个解决方案更好
文章图片
Java:Java 线程不安全分析,同步锁和Lock机制,哪个解决方案更好
文章图片
Java:Java 线程不安全分析,同步锁和Lock机制,哪个解决方案更好
文章图片
Java:Java 线程不安全分析,同步锁和Lock机制,哪个解决方案更好
文章图片
Java:Java 线程不安全分析,同步锁和Lock机制,哪个解决方案更好
文章图片
【Java:Java 线程不安全分析,同步锁和Lock机制,哪个解决方案更好】
Java:Java 线程不安全分析,同步锁和Lock机制,哪个解决方案更好
文章图片

Java 线程不安全分析
线程不安全
线程不安全的问题分析:在小朋友抢气球的案例中模拟网络延迟来将问题暴露出来;示例代码如下:
模拟网络延迟演示线程不安全
在线程中的run方法上不能使用throws来声明抛出异常 , 所以在run方法中调用有可能出现异常的代码时 , 只能使用try-catch将其捕获来处理 。
原因是:子类覆盖父类方法时不能抛出新的异常 , 父类的run方法都没有抛出异常 , 子类就更加不能抛出异常了 。 详情可查看我的另一篇文章 :Java基础之异常处理机制
在上述案例中 , 通过引入Thread.sleep();来模拟网络延迟 , 该方法的作用是让当前线程进入睡眠状态10毫秒 , 此时其他线程就可以去抢占资源了 , 方法的参数是睡眠时间 , 以毫秒为单位 。
通过观察运行结果 , 发现了问题:
小红、小强两个小朋友都抢到了14号气球
在运行结果中 , 小红、小强两个小朋友都抢到了14号气球 , 也就是14号气球被抢到了2次 。 我们来梳理线程的运行过程来看看发生了什么:

  1. 小强和小红两个线程都拿到了14号气球 , 由于线程调度 , 小强获得了CPU时间片 , 打印出了抢到的气球 , 而小红则进入睡眠;小强在打印后对num做了减一操作 , 此时num为13;

  2. 小明线程开始运行 , 抢到了13号气球 , 并对num做了减一操作 , 此时num为12;

  3. 小红线程醒来 , 打印出抢到的14号气球;此时的num为12 , 减一后结果为11;

  4. 由于多个线程是并发操作 , 所以对num做判断时可能上一个线程还未对num减一 , 所以都能通过(num > 0)的判断;

然后再来运行上述代码 , 得出如下的结果:

运行结果中出现了本不该出现的0 和 -1
运行结果中出现了本不该出现的0和-1 , 因为按照正常逻辑 , 气球数量到1之后就不应该被打印和减一了 。 出现这样的结果是因为出现了以下的执行步骤: