欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 维修 > JUC笔记之ReentrantLock

JUC笔记之ReentrantLock

2025/2/24 7:32:29 来源:https://blog.csdn.net/m0_75113406/article/details/143513445  浏览:    关键词:JUC笔记之ReentrantLock

ReentrantLock

相对于synchronized它具备如下特点

· 可中断

· 可以设置超时时间

· 可以设置为公平锁

· 支持多个条件变量(多个wait set,不同于synchronized的wait set,ReentrantLock的wait set在同一条件下notify才能唤醒WATING状态的线程)

与synchronized一样,都支持可重入

基本语法

//获取锁
ReentrantLock reentrantLock = new ReentrantLock();
reentrantLock.lock();
try{//临界区
}finally{//释放锁reentrantLock.unlock();
}

可重入

可重入是指同一个线程如果首次获得了这把锁,那么因为它是这把锁的持有者,因此有权力再次获取这把锁。如果是不可重入锁,那么第二次获得锁时,自己也会被锁挡住

代码体现

@Slf4j(topic = "c.Demo")
public class Demo {private static ReentrantLock reentrantLock = new ReentrantLock();public static void main(String[] args) {reentrantLock.lock();try {log.debug("enter main");m1();}finally {reentrantLock.unlock();}}public static void m1(){reentrantLock.lock();try {log.debug("enter m1");m2();}finally {reentrantLock.unlock();}}public static void m2(){reentrantLock.lock();try {log.debug("enter m2");}finally {reentrantLock.unlock();}}
}

可打断

用lockInterruptibly()来生成的锁才能打断

代码体现

@Slf4j(topic = "c.Demo2")
public class Demo2 {private static ReentrantLock lock = new ReentrantLock();public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {try {//如果没有竞争那么此方法就会获取lock对象锁//如果有竞争就进入阻塞队列,可以被其他线程用 interruput 方法打断log.debug("尝试获得锁");lock.lockInterruptibly();} catch (InterruptedException e) {e.printStackTrace();log.debug("没有获得到锁");return;}try {log.debug("获取到锁");}finally {lock.unlock();}}, "t1");lock.lock();t1.start();Thread.sleep(1000);log.debug("打断 t1");t1.interrupt();}
}

锁超时

立刻失败

@Slf4j(topic = "c.Demo3")
public class Demo3 {private static ReentrantLock lock = new ReentrantLock();public static void main(String[] args) {Thread t1 = new Thread(()->{log.debug("尝试获得锁");if (!lock.tryLock()) {log.debug("获取不到锁");return;}try {log.debug("获取到锁");}finally {lock.unlock();}},"t1");lock.lock();log.debug("获取到锁");t1.start();}}

含超时时间的

@Slf4j(topic = "c.Demo3")
public class Demo3 {private static ReentrantLock lock = new ReentrantLock();public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(()->{log.debug("尝试获得锁");try {if (!lock.tryLock(2, TimeUnit.SECONDS)) {log.debug("获取不到锁");return;}} catch (InterruptedException e) {e.printStackTrace();log.debug("获取不到锁");return;}try {log.debug("获取到锁");}finally {lock.unlock();}},"t1");lock.lock();log.debug("获取到锁");t1.start();Thread.sleep(1000);log.debug("释放了锁");lock.unlock();}}

用ReentrantLock解决哲学家用餐问题

筷子类

class Chopstick extends ReentrantLock {String name;public Chopstick(String name) {this.name = name;}@Overridepublic String toString() {return "Chopstick{" +"name='" + name + '\'' +'}';}
}

哲学家类

@Slf4j(topic = "c.Philosopher")
class Philosopher extends Thread{Chopstick left;Chopstick right;public Philosopher(String name, Chopstick left, Chopstick right){super(name);this.left = left;this.right = right;}@Overridepublic void run() {while (true){//尝试获得左手筷子if (left.tryLock()) {try {//尝试获取右手筷子if (right.tryLock()) {try {eat();}finally {right.unlock();}}}finally {left.unlock();//释放手里的左筷子}}}}private void eat(){log.debug("eating...");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}
}

test类

@Slf4j(topic = "c.SoleDeadLockDemo")
public class SoleDeadLockDemo {public static void main(String[] args) {Chopstick c1 = new Chopstick("1");Chopstick c2 = new Chopstick("2");Chopstick c3 = new Chopstick("3");Chopstick c4 = new Chopstick("4");Chopstick c5 = new Chopstick("5");new Philosopher("哲学1",c1,c2).start();new Philosopher("哲学2",c2,c3).start();new Philosopher("哲学3",c3,c4).start();new Philosopher("哲学4",c4,c5).start();new Philosopher("哲学5",c5,c1).start();}
}

公平锁

ReentrantLock默认是不公平的,但是可以通过构造方法改成公平的

ReentrantLock reentrantLock = new ReentrantLock(true);

公平锁一般没有必要,会降低并发度。

条件变量

synchronized中也有条件变量,就是waitSet休息室,当条件不满足时进入waitSet等待

ReentrantLock的条件变量比synchronized强大之处在于,它是支持多个条件变量的,这就好比

· synchronized是那些不满足条件的线程都在一间休息室等消息

· 而ReentrantLock支持多间休息室,唤醒时也是按休息室来唤醒

使用流程

· await前需要获取锁

· await执行后,会释放锁,进入conditionObject等待

· await的线程被唤醒(或打断、或超时)取重新竞争lock锁

· 竞争lock锁成功后,从await后继续执行

@Slf4j(topic = "c.Demo5")
public class Demo5 {static final ReentrantLock lock = new ReentrantLock();static private boolean hasSmoke = false;static private boolean hasEat = false;static Condition smoke = lock.newCondition();static Condition eat = lock.newCondition();public static void main(String[] args) throws InterruptedException {new Thread(()->{lock.lock();try {log.debug("有烟没");while (!hasSmoke) {log.debug("没烟我先休息");try {smoke.await();} catch (InterruptedException e) {e.printStackTrace();}}log.debug("有烟,那没事了");}finally {lock.unlock();}},"小男").start();new Thread(()->{lock.lock();try {log.debug("有饭没");while (!hasEat){log.debug("没饭我先休息了");try {eat.await();} catch (InterruptedException e) {e.printStackTrace();}}log.debug("有饭那没事了");}finally {lock.unlock();}},"小女").start();Thread.sleep(1000);new Thread(()->{lock.lock();try {log.debug("送饭的到了");hasEat = true;eat.signal();}finally {lock.unlock();}},"送饭的").start();Thread.sleep(1000);new Thread(()->{lock.lock();try {log.debug("送烟的到了");hasSmoke = true;smoke.signal();}finally {lock.unlock();}},"送烟的").start();}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词