ReentrantLock讲解

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

常用方法:

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

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



     ReentrantLock reentrantLock = new ReentrantLock();

     Condition condition = reentrantLock.newCondition();

        new Thread(() -> {
            try {
                reentrantLock.lock();
                    condition.await();
                    System.err.print(1);
            } catch (Exception e) {

            } finally {
                reentrantLock.unlock();
            }

        }).start();


         reentrantLock.lock();
         condition.signal();
         reentrantLock.unlock();
         

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

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

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

          ReentrantLock reentrantLock = new ReentrantLock();

         AtomicBoolean atomicBoolean=new AtomicBoolean(false);
        Condition condition = reentrantLock.newCondition();
        ExecutorService executorService = Executors.newFixedThreadPool(3);

        executorService.submit(()->{
           //处理数据,得到最后可以写入的数据

            //执行写入操作
            reentrantLock.lock();
            while (!前一批数据是否已经写入){
                condition.await();
            }
            当前批数据写入状态=true;
            下一批数据的condition.signal();//唤醒下一批数据的condition,使其进入阻塞状态,执行写入操作
            reentrantLock.unlock(); //解锁,让下一个线程可以执行写入操作

        });

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

你可能感兴趣的:(JUC,java,开发语言)