在我的理解中ReentrantLock和synchronized最大的区别就是条件变量的控制,我们知道synchronized中如果想实现条件不满足进行等待状态,是通过waitset和wait()和notify()来实现的,但是有一个问题,所有的等待线程全部都会放在一个里边,这样一来,当我们想唤醒的时候,就会唤醒很多不必要的线程,而ReentrantLoct为我们提供了condition,可以通过ReentrantLock.newCondition()来创建多个等待区,来实现更为复杂的操作!
- //锁住当前线程,如果有新的线程进来后,没有获取到锁,则进入阻塞队列,可以被别的线程打断
- reentrantLock.lock();
- //锁住当前线程,如果有新的线程进来后,没有获取到锁,则进入阻塞队列,不可被别的线程打断
- reentrantLock.lockInterruptibly();
- //锁住当前线程,如果有新的线程进来后,没有获取到锁,则返回false需要在程序中进行处理,直接返回方法或者别的操作,这里还可以设置获取锁等待时间,若指定时间内没有获取到,则返回false
- reentrantLock.tryLock();
- //解锁
- reentrantLock.unLock();
- //获取等待队列
- reentrantLock.newCondition()
-
-
-
- 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,现在有一批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判断,那么如果第一次前一批还未写入,则线程就会继续往下运行了,违背了我们的原则,写为循环,,不管哪个线程先获取到锁,都可以实现我们想要的效果