当前位置: 首页 > article >正文

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;
    }

    @Override
    public 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;
    }

    @Override
    public 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();
    }
}

http://www.kler.cn/a/382277.html

相关文章:

  • Memento 备忘录模式
  • Rancher的安装
  • 小语言模型介绍与LLM的比较
  • vue3动态监听div高度案例
  • Jmeter命令监控CPU等指标
  • qt QWizard详解
  • 基础 IO(文件系统 inode 软硬链接)-- 详解
  • 从SSL到TLS——互联网传输的护卫军
  • 程序中怎样用最简单方法实现写excel文档
  • Dubbo详解及其应用
  • SpringBoot在线教育系统:微服务架构
  • EPSON机械手与第三方相机的校准功能设计By python
  • 高亚科技签约酸动力,助力研发管理数字化升级
  • 【制造业&仓库】流水线能源设备检测系统源码&数据集全套:改进yolo11-DCNV2-Dynamic
  • 【Golang】Golang的Map的线程安全问题
  • 01 Oracle 数据库存储结构深度解析:从数据文件到性能优化的全链路探究
  • 【论文速看】DL最新进展20241106-图像分类、图像分割、时间序列预测
  • 【p2p、分布式,区块链笔记 Torrent】WebTorrent的add和seed函数
  • 数字后端零基础入门系列 | Innovus零基础LAB学习Day8
  • 【vue-pdf】简单封装pdf预览组件
  • Linux信号_信号的保存
  • 应用层知识点总结2
  • 华为海思招聘-芯片与器件设计工程师-模拟芯片方向- 机试题-真题套题题目——共8套(每套四十题)
  • 一文了解CANFD基础
  • 5种AI合同审查方法,免费开源,提升50%法律文件比对效率
  • 在 hiveSQL 中判断一个字段是否包含某个值