• ReentrantLock讲解


    在我的理解中ReentrantLock和synchronized最大的区别就是条件变量的控制,我们知道synchronized中如果想实现条件不满足进行等待状态,是通过waitset和wait()和notify()来实现的,但是有一个问题,所有的等待线程全部都会放在一个里边,这样一来,当我们想唤醒的时候,就会唤醒很多不必要的线程,而ReentrantLoct为我们提供了condition,可以通过ReentrantLock.newCondition()来创建多个等待区,来实现更为复杂的操作!

    常用方法:

    1. //锁住当前线程,如果有新的线程进来后,没有获取到锁,则进入阻塞队列,可以被别的线程打断
    2. reentrantLock.lock();
    3. //锁住当前线程,如果有新的线程进来后,没有获取到锁,则进入阻塞队列,不可被别的线程打断
    4. reentrantLock.lockInterruptibly();
    5. //锁住当前线程,如果有新的线程进来后,没有获取到锁,则返回false需要在程序中进行处理,直接返回方法或者别的操作,这里还可以设置获取锁等待时间,若指定时间内没有获取到,则返回false
    6. reentrantLock.tryLock();
    7. //解锁
    8. reentrantLock.unLock();
    9. //获取等待队列
    10. reentrantLock.newCondition()

    如何通过condition来实现线程的等待呢?

    1. ReentrantLock reentrantLock = new ReentrantLock();
    2. Condition condition = reentrantLock.newCondition();
    3. new Thread(() -> {
    4. try {
    5. reentrantLock.lock();
    6. condition.await();
    7. System.err.print(1);
    8. } catch (Exception e) {
    9. } finally {
    10. reentrantLock.unlock();
    11. }
    12. }).start();
    13. reentrantLock.lock();
    14. condition.signal();
    15. reentrantLock.unlock();

    上边就是一个很简单的例子,首先是创建一个子线程来模拟需要等待的线程,然后当它调用await()方法后则进入等待状态并释放锁,然后主线程就可以获取到锁了,主线程拿到锁以后则让上边的线程停止等待,再次去竞争锁,进入阻塞状态,然后等待获取到锁以后执行输出1的操作

    通过condition可以解决什么问题?

    在我的开发中,我觉得有这样一个场景会用到condition,现在有一批l数据,数据量很大,想导出为excel,这里用到了线程池,希望通过线程池分批去导出,这样可以防止内存溢出,但是同时我们希望写入的数据依旧按照一定顺序去导入,那么我们就可以把最终写的操作加上锁,同一时间只能一个线程操作,但是这里还没有实现顺序插入,然后就是我们今天的主角condition,比如这里我们通过页码来区分顺序,那么我们可以把每一批数据的首页,作为该批数据的标志,每一批数据对应着两个参数,一个是是否插入另一个是处理该批数据线程的condition,当处理完数据,可以往excel写入时,每一个往进写时都要判断是否前一批数据已经写入,如果没写则当前线程进入等待状态,如果已经写了,那么则把当前数据写入,并设置该批数据写入状态为true,唤醒下一批数据的等待线程,下面给出一个伪代码

    1. ReentrantLock reentrantLock = new ReentrantLock();
    2. AtomicBoolean atomicBoolean=new AtomicBoolean(false);
    3. Condition condition = reentrantLock.newCondition();
    4. ExecutorService executorService = Executors.newFixedThreadPool(3);
    5. executorService.submit(()->{
    6. //处理数据,得到最后可以写入的数据
    7. //执行写入操作
    8. reentrantLock.lock();
    9. while (!前一批数据是否已经写入){
    10. condition.await();
    11. }
    12. 当前批数据写入状态=true;
    13. 下一批数据的condition.signal();//唤醒下一批数据的condition,使其进入阻塞状态,执行写入操作
    14. reentrantLock.unlock(); //解锁,让下一个线程可以执行写入操作
    15. });

    上边为什么用while循环,如果不用的话,换为if判断,那么如果第一次前一批还未写入,则线程就会继续往下运行了,违背了我们的原则,写为循环,,不管哪个线程先获取到锁,都可以实现我们想要的效果

  • 相关阅读:
    debian无法使用reboot 等系统命令解决
    智能合约语言(eDSL)—— 如何使用wasmtime运行合约
    数据结构-顺序存储二叉树
    怎样选择合适的CRM客户管理系统?
    方程组线性化方法和牛顿迭代法基础
    《java练级之路》多态!!!
    AI外呼机器人是怎么做到高效触客?效果如何?
    react中预览excel表格
    Qt+ECharts开发笔记(一):ECharts介绍、下载和Qt调用ECharts基础柱状图Demo
    Hyper-V 安装windows10 虚拟机,且能调试窗口大小、与主机之间复制文件
  • 原文地址:https://blog.csdn.net/weixin_59244784/article/details/133772925