显式锁简介
java5.0之前,在协调对共享对象的访问时可以使用的机制只有synchronized和volatile,java5.0增加了一种新的机制:ReentrantLock。
锁像synchronized同步块一样,是一种线程同步机制,与synchronized不同的是ReentrantLock提供了一种无条件的、可轮询的、定时的以及可以中断的锁获取操作,并且所有的加锁和解锁的方法都是显式的,所以也叫显式锁。
synchronized的实现中包含了锁机制,但是锁的获取和释放不能人为的进行控制,所以当我们要定时获取锁,检测锁是否被占用时就应当使用显式锁。
显式锁涉及的类和接口
ReentrantLock实现了Lock接口,位于Java的J.U.C包中,包含了一下几个主要方法:
1、void lock(),获取锁;
2、void unlock(),释放锁;
3、boolean trylock(),仅在调用时锁为空闲状态才获取该锁;
4、boolean tryLock(long time, TimeUnit unit),如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁。
显式锁的简单使用
下面我们就分别使用synchronized和lock实现小红借书的需求。
需求:小明和小红去借书,每人借10本。一个人借完之后才允许另外一个人借。
分析:
1、小明和小红相当于 2个线程;
2、借10本书视为一个操作即循环10次;
3、一个人借完之后才允许另外一个人借。
要实现必须保证借书的10次操作中间不能发生线程的切换,因此可以使用 synchronized 同步块或显示锁 ReentrantLock 来保证。
synchronized方式
ReentrantLock方式
本案例中在lock 和unlock 中间的代码块与synchronized 包裹的代码块是等效的。可以保证在执行unlock之前该线程不会让出资源给其它线程执行。
实现轮询锁
需求:小明和小红去借书,但是书只有一本,假如小明借到了,看完这本书需要5秒,
在小明读书的时间内,小红还会多次去借书,直到小明归还小红才能借到。
分析:
1、小明和小红去借书,但是书只有一本 ,从这里可以分析出需要两个线程;
2、假如小明借到了,看完这本书需要5秒,借到书可以视为获取到锁;
3、在小明读书的时间内,小红还会多次去借书,可以视为小红未获得锁,所以需要多次尝试去获得锁;
4、直到小明归还小红才能借到,可以视为小明的线程释放锁,小红获得锁。
总结
不论使用synchronized 还是使用显示锁lock都可以解决代码块同步的问题。synchronized 使用更方便,获得锁和释放锁不需要手动处理,但控制粒度不够细致。lock显式锁需要使用lock()手动加锁,unlock()手动释放锁,使用起来相对复杂,但可以实现更精细的锁控制。
使用trylock结合轮询可以实现检测锁是否空闲的效果。
原文发布时间为:2018-11-13