Java与MySQL中的锁以及保证线程安全的方式

1 概述

无论是存在硬盘里的数据还是存在内存中的数据,只要不是像Redis那样只支持单线程访问,就都存在线程安全问题。通常,在代码中,面对线程安全问题的态度,分为【悲观】和【乐观】。本文从这两个角度对Java与MySQL中的锁及保证线程安全的方式进行一个对比,尽量提炼出其中的相似之处。文中的某些地方会把Java中的【线程】与MySQL中的【事务】统称为【线程】。

2 悲观

【悲观】认为,在当前环境下,极有可能发生线程安全问题,因此,需要把多线程共享的数据上一个重锁,在某个线程拥有这个数据的锁期间,其他线程无法对这个数据进行访问与操作。

2.1 Java的悲观锁

Java里面著名的synchronizedReentrantLock就是悲观锁。一旦某个线程抢到了这个资源,其他线程就得等待了。可以保证线程安全,但是会拖慢系统速度——速度和安全向来是一对矛盾的概念。

例如,HashMap这个集合,线程A、B同时进行put()操作,他俩的节点映射在了同一数组下标。A执行到最后一步刚要把节点加在链表后面时,被挂起了。这时B把自己的节点加在了链表后面。然后A继续操作,就把B节点覆盖掉了。

为了解决这个问题,Java加入了HashTable。它和HashMap唯一的区别就是在get和put等关键方法上面加了synchronized修饰。从此两个put线程再也进不去同一个HashTable,保障了线程安全。

2.2 MySQL里的悲观锁

MySQL的事务隔离级别中,最高级别的串行化可以保证线程安全。例如这个简易的收益表:
Java与MySQL中的锁以及保证线程安全的方式_第1张图片
在事务A加数剧的时候,事务B别说对表进行写操作了,他连读都读不了。此时线程很安全。

2.3 减小悲观锁的粒度

2.3.1 Java代表:ConcurrentHashMap

ConcurrentHashMap保证线程安全的方式相当复杂,这里举例一种较简单的情况:ConcurrentHashMap已经被成功new出来,线程A和线程B分别要put一个结点,它们分别被映射到了数组下表为1和3的地方。

你可能感兴趣的:(java,mysql,经验分享)