线程安全问题的解决方案

126 阅读2分钟

话不多说,开整。

  • 锁 前面也说过,线程安全的问题的出现,是因为在多线程并发执行操作临界资源的时候,会可能引发临界资源的安全问题。如果有不懂的,可以查看我前面的文章。对JAVA多线程安全问题的理解 - 掘金 (juejin.cn) 。要解决线程安全的问题,就从根本出发,解决临界资源的同时访问。保证只有一个线程访问完了之后,才给另一个线程访问。这样就不会两个线程抢着一个资源访问了,就可以保证线程的安全。怎么做到呢,就引入了一个概念,锁。

  • 锁的概念 锁是什么呢,就是锁住,当线程访问资源的时候,给他一把锁,锁住了其他线程就无法访问了。这样就可以保证线程在使用资源的时候,其他线程无法访问。

  • 锁,锁哪里呢?

    锁,就是锁住资源,可以是对象,或者是变量。给资源上锁,资源就被拥有这把锁的线程占有。

  • 锁的类型

  1. 乐观锁:顾名思义,比较乐观的锁,就是在更新操作的时候判断一下别的线程是否修改了数据,如果修改了数据就放弃更新。否则继续执行。
  2. 悲观锁:顾名思义,就是悲观的锁,就是自己操作数据时候会认为别的线程在跟自己抢资源,这个时候不允许任何其他线程抢资源,直到自己操作完毕,才释放锁,让给其他线程。
  • 乐观锁的实现
  1. CAS (compare and swap) ----比较和交换。 cas也叫做自旋锁,因为他如果操作不成功,会一直重试,有一种循环的概念,所以叫自旋锁。 就是比较内存的预期值跟理想值是否一样,一样就继续操作,否则放弃操作。

有人会说,cas有两个操作,比较和交换。怎么保证这两个操作的原子性呢。这就是利用了cpu支持的原子操作,在硬件层面保证的。

一般是在数据表中加入一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version指会加一。当线程A要重新更新数据值时,在读取数据的时候也会读取version值,在提交更新时,若刚才读取到的version值与当前数据库中的version值相等才更新,否则重新更新操作,直到更新成功。

2.版本号机制,这里先不做阐述了。