并发编程的个人理解

不管现实多么惨不忍睹,都要持之以恒地相信,这只是黎明前短暂的黑暗而已。不要惶恐眼前的难关迈不过去,不要担心此刻的付出没有回报,别再花时间等待天降好运。真诚做人,努力做事!你想要的,岁月都会给你。并发编程的个人理解,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

并发出现的情况

情况一:CPU调度导致
这种情况,相当于CPU切断了我的代码,局部变量,线程安全,但这个变量可能是从数据库,缓存等地方读取出来的,读取的数据已经因为CPU调度的问题,已经被其他的线程更改掉了。个人觉得这种情况是不可重复读的概念,导致的并发问题
这不仅仅是多线程可能出现的问题,就算我是单线程,处理延迟也可能导致
例如:我读取库存数量为1,10秒钟后,我再去减掉库存。但是我手动更改了数据表,库存变成了0,10秒钟,库存被程序执行了-1操作照样导致了问题的产生。这个时候从JVM层面就处理不了,需要通过mysql的锁操作

CPU的调度时间片可能会把代码切割成几片进行执行
例如切成了两片,下一片的的数据需要使用上一片读取处理的共享数据
在这期间,有其他的线程过来,改掉了这个数据
下一片代码片执行的时候,共享变量已经被其他线程改变了,导致结果与预期不一致
在这里插入图片描述


情况二:共享变量读取与修改
也是CPU调度了,但是属于JVM层面的并发,共享变量数据被改掉了。A线程读取,B线程改掉了共享变量值,A不知道继续使用读取的数据。导致结果异常

情况三:共享变量在工作内存与核心内存的处理
这种情况,又有点区别,虽然也是不可以重复读,但并不是我自己写代码的读取与修改,而是站在内存方面,修改的共享变量的时候,需要先去读取数据然后再更改。还是读取与修改两个操作不是原子性的
我需要修改某一个变量,例如:hashmap,我虽然是只有写入的代码,但是从内存的角度来看,内存是需要先把变量从核心内存读入工作内存中,然后工作内存里面操作完毕后,再放回去。 这个是其他的线程已经改过了这个数据,你修改完毕后放回去,相当于把其他线程辛辛苦苦修改的给覆盖掉了


总结

  1. 在学习锁的时候,要考虑的并不是单纯的从JVM层面去锁定代码或者数据库层面去考虑数据库锁,而是要分情况。
  2. 本质都是不可以重复读取那么我在读的时候跟用的时候,必须达到原子性,也就是说读取跟使用要锁到一起。

使用

那么基于总结,我什么时候加锁呢?

  1. 碰到共享变量(类变量,实例变量),考虑加锁

    • 代码中存在共享变量的读取与使用,考虑锁
      锁方案:读取跟使用这一段代码锁起来。
      单个JVM使用代码锁(synchronized,reentrantLock)
      多个JVM 考虑第三方介入(例如:redis的单线程,一次只能一个线程来执行代码)

    • 对共享变量进行增删改,考虑锁
      锁方案:

      1. 使用安全类型(hashmap 改为 concurrentHashMap)
      2. 操作的时候用代码锁起来,也是让它每次只能被一个线程操作。

  2. 操作的变量不是共享变量,但数据来源于第三方(数据库),读取后要需要去使用它
    锁方案:读取与使用的过程中锁起来。

    • 可以考虑数据库锁,读取的时候锁起来这个数据,不能进行更改,使用完毕后释放锁 这里我们只讨论锁的使用情况,乐观锁属于锁优化,所以不考虑乐观锁方案
    • 如果没有其他地方会更改,使用代码锁也行。

如有理解不到位,请指正

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/181708.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!