
目录
-
-
-
- 一、特点
- 二、代码示例
-
- 2.1 可重入
- 2.2 可打断
- 2.3 可超时
- 2.4 公平锁
- 2.5 条件变量
一、特点
- 1.可中断:线程2可以让线程1获取的锁取消掉
- 2.可以设置超时时间:规定时间内,线程1争抢不了锁,可以放弃锁的竞争
- 3.可以设置为公平锁:竞争不到锁的线程在等待过程中,当锁释放后,谁先等待的谁先得到锁(先进先出);如果随机去争抢,线程太多可能有些线程始终抢不到锁,会造成线程饥饿
- 4.支持多个条件变量:synchronized中对象的monitor有个waitset,ReentrantLock支持多个waitset
- 5.可重入:同一个线程获得了锁,未释放锁,可以再次获得这把锁
二、代码示例
2.1 可重入
package com.learning.lock;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.locks.ReentrantLock;
/* @Author wangyouhui* @Description ReentrantLock 可重入/
@Slf4j
public class ReentrantLockLearning {private static ReentrantLock reentrantLock = new ReentrantLock();public static void main(String[] args) {reentrantLock.lock();try{log.info("main");method1();}finally {reentrantLock.unlock();}}public static void method1(){reentrantLock.lock();try{log.info("method1");method2();}finally {reentrantLock.unlock();}}public static void method2(){reentrantLock.lock();try{log.info("method2");}finally {reentrantLock.unlock();}}
}
2.2 可打断
- 1.lock方法是不能被打断的,使用lockInterruptibly方法支持可打断
- 2.如果没有竞争,lockInterruptibly方法会获取对象锁
- 3.如果有竞争,则进入阻塞队列,可以被其它线程用interrupt方法打断
- 4.使用线程的interrupt方法即可打断
- 5.可以使用打断来防止线程无限制的等待下去,可以避免死锁的发生
package com.learning.lock;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.locks.ReentrantLock;/* @Author wangyouhui* @Description ReentrantLock 可打断/
@Slf4j
public class ReentrantLockInterruptLearning {private static ReentrantLock reentrantLock = new ReentrantLock();public static void main(String[] args) throws InterruptedException {Thread thread1 = new Thread(() -> {try {log.info("尝试获得锁");reentrantLock.lockInterruptibly();} catch (InterruptedException e) {e.printStackTrace();log.info("线程1未获取到锁,等待中被打断");return;}try {log.info("线程1获取到锁");}finally {// 释放锁reentrantLock.unlock();}}, "thread1");// 主线程获得锁log.info("主线程获得锁");reentrantLock.lock();thread1.start();log.info("线程1未获得锁在等待");Thread.sleep(2000);log.info("主线程打断线程1");thread1.interrupt();}
}
2.3 可超时
- 1.tryLock可以尝试获取锁,可以在指定时间内获取锁
- 2.tryLock可以被其它线程打断
- 3.其它线程获取到锁,然后释放锁,只要时间小于tryLock的时间,尝试获取锁还是可以成功的
package com.learning.lock;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;/* @Author wangyouhui* @Description 锁超时/
@Slf4j
public class ReentrantLockTimeoutLearning {private static ReentrantLock reentrantLock = new ReentrantLock();public static void main(String[] args) throws InterruptedException {Thread thread1 = new Thread(()->{log.info("线程1尝试获取锁");try {if (!reentrantLock.tryLock(2, TimeUnit.SECONDS)) {log.info("线程1没有获取到锁");return;}} catch (InterruptedException e) {e.printStackTrace();log.info("线程1没有获取到锁");return;}try {log.info("线程1获取到锁");}finally{log.info("线程1释放锁");reentrantLock.unlock();}}, "thread1");log.info("主线程先获得锁");reentrantLock.lock();thread1.start();Thread.sleep(1000);log.info("主线程释放锁");reentrantLock.unlock();}
}
2.4 公平锁
- 1.默认是不公平锁
- 2.先加锁的优先获得cpu的时间片
- 3.一般没有必要设置为公平锁,会降低并发度
package com.learning.lock;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockFair {private static Lock lock = new ReentrantLock(true); // true表示公平锁private static Condition condition = lock.newCondition();public static void main(String[] args) {for (int i = 0; i < 5; i++) {new Thread(() -> {lock.lock();try {System.out.println(Thread.currentThread().getName() + "获得了锁");condition.await();System.out.println(Thread.currentThread().getName() + "被唤醒了");} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}, "线程" + i).start();}try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}lock.lock();try {condition.signalAll();System.out.println("唤醒所有线程");} finally {lock.unlock();}}
}
2.5 条件变量
- 1.synchronized中的条件变量waitSet,当条件不满足时,线程进入waitSet等待
- 2.ReentrantLock的条件变量支持多个,synchronized不满足条件的线程都在同一个waitSet中等待,ReentrantLock可以让不同条件不满足的线程在不同的地方等待
package com.learning.lock;import lombok.extern.slf4j.Slf4j;import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;@Slf4j
public class ReentrantLockCondition {private static ReentrantLock lock = new ReentrantLock();private static Condition condition1 = lock.newCondition();private static Condition condition2 = lock.newCondition();public static void main(String[] args) throws InterruptedException {Thread thread1 = new Thread(() -> {try {lock.lock();log.info("线程1获取到锁");try {log.info("线程1获取到锁不满足条件而等待");condition1.await();log.info("线程1满足条件继续执行");} finally {lock.unlock();log.info("线程1释放锁");}} catch (InterruptedException e) {e.printStackTrace();}}, "线程1");thread1.start();Thread thread2 = new Thread(() -> {try {lock.lock();log.info("线程2获取到锁");try {log.info("线程2获取到锁不满足条件而等待");condition2.await();log.info("线程2满足条件继续执行");} finally {lock.unlock();log.info("线程2释放锁");}} catch (InterruptedException e) {e.printStackTrace();}}, "线程2");thread2.start();Thread.sleep(1000);lock.lock();try {log.info("条件1满足,唤醒线程1");condition1.signal();} finally {lock.unlock();}lock.lock();try {log.info("条件2满足,唤醒线程2");condition2.signal();} finally {lock.unlock();}}
}
