ReentrantLock
与 synchronized的异同点:
相同:都支持可重入
可重入:可重入是指同一个线程如果首次获得了这把锁,那么因为它是这把锁的拥有者,因此有权利再次获取这把锁 如果是不可重入锁,那么第二次获得锁时,自己也会被锁挡住
@Slf4j(topic = "c.TestReentrant")
public class TestReentrant {static ReentrantLock lock = new ReentrantLock();public static void main(String[] args) {method1();}public static void method1() {lock.lock();try {log.debug("execute method1");method2();} finally {lock.unlock();}}public static void method2() {lock.lock();try {log.debug("execute method2");method3();} finally {lock.unlock();}}public static void method3() {lock.lock();try {log.debug("execute method3");} finally {lock.unlock();}}
}
不同:对于 synchronized它具备如下特点
可中断
两个线程同时去争一把锁的情况下,可以避免让没获取到的一直处于等待状态
lockInterruptibly()
demo如下:
package concurrent.reentrantlock;import lombok.extern.slf4j.Slf4j;import java.util.concurrent.locks.ReentrantLock;import static util.Sleeper.sleep;@Slf4j(topic = "c.TestInterrupt")
public class TestInterrupt {public static void main(String[] args) {test2();}private static void test2() {ReentrantLock lock = new ReentrantLock();Thread t1 = new Thread(() -> {log.debug("启动...");lock.lock();try {log.debug("获得了锁");} finally {lock.unlock();}}, "t1");lock.lock();log.debug("获得了锁");t1.start();try {sleep(1);t1.interrupt();log.debug("执行打断");sleep(1);} finally {log.debug("释放了锁");lock.unlock();}}private static void test1() {ReentrantLock lock = new ReentrantLock();Thread t1 = new Thread(() -> {log.debug("启动...");try {lock.lockInterruptibly();} catch (InterruptedException e) {e.printStackTrace();log.debug("等锁的过程中被打断");return;}try {log.debug("获得了锁");} finally {lock.unlock();}}, "t1");lock.lock();log.debug("main 获得了锁");t1.start();try {sleep(1);t1.interrupt();log.debug("main 执行打断");} finally {lock.unlock();}}
}
可以设置超时时间
tryLock(1, TimeUnit.SECONDS)
package concurrent.reentrantlock;import lombok.extern.slf4j.Slf4j;import java.util.concurrent.locks.ReentrantLock;import static util.Sleeper.sleep;@Slf4j(topic = "c.TestInterrupt")
public class TestInterrupt {public static void main(String[] args) {test1();}private static void test2() {ReentrantLock lock = new ReentrantLock();Thread t1 = new Thread(() -> {log.debug("t1 启动...等锁中");lock.lock();try {log.debug("获得了锁");} finally {lock.unlock();}}, "t1");lock.lock();log.debug("获得了锁");t1.start();try {sleep(1);t1.interrupt();log.debug("执行打断");sleep(1);} finally {log.debug("释放了锁");lock.unlock();}}private static void test1() {ReentrantLock lock = new ReentrantLock();Thread t1 = new Thread(() -> {log.debug("启动...");try {lock.lockInterruptibly();} catch (InterruptedException e) {e.printStackTrace();log.debug("等锁的过程中被打断");return;}try {log.debug("获得了锁");} finally {lock.unlock();}}, "t1");lock.lock();log.debug("main 获得了锁");t1.start();try {sleep(1);t1.interrupt();log.debug("main 执行打断");} finally {lock.unlock();}}
}
可以设置为公平锁
公平锁一般没有必要,会降低并发度;可以使用tryLock()去设置超时时间。
支持多个条件变量
送烟、送外卖的例子;
多个条件变量,对应多个等待区;