Java 锁的使用方式主要有两种:轻量级的 synchronized 和主动的 Lock (如 ReentrantLock ),由于 synchronized 看不到源码实现,所以我们只说主动的 Lock。以 ReentrantLock 为例,来说明下 Java 的代码如何被锁住。
我们写锁的代码一般如下:
通过 lock 方法锁住,然后执行 do something ,最后通过 unLock 释放,那么 //do something 的代码是如何被锁住的,如何保证只有一个线程可以执行的呢?为此我们细分下面几个问题:
我们需要锁住什么?
锁住是什么意思?
如何锁住的?
如何释放的?
AQS的两种队列详解
锁的设计思路
我们需要锁住什么?
总的来说,我们需要锁住的都是共享变量,保证共享变量在同一时刻只能被一个线程去写值。
平时工作场景中,需要锁住的共享变量主要是两大类:
被 static 修饰的全局变量;
被 spring 单例容器托管下,springBean 的局部变量。
我们举例来说明下:
从打印的结果来看,多个线程对共享变量进行写操作时,如果没有进行锁的控制,存在着值被覆盖的问题。
下图是加锁之后的实现:
我们引入了 ReentrantLock 锁来把对共享变量的访问控制,保证在同一时刻只会有一个线程对共享变量进行写入操作。