ReentrantLock与Condition


参考博文1

1.ReentrantLock函数列表

// 创建一个 ReentrantLock ,默认是“非公平锁”。
ReentrantLock()
// 创建策略是fair的 ReentrantLock。fair为true表示是公平锁,fair为false表示是非公平锁。
ReentrantLock(boolean fair)

// 查询当前线程保持此锁的次数。
int getHoldCount()
// 返回目前拥有此锁的线程,如果此锁不被任何线程拥有,则返回 null。
protected Thread getOwner()
// 返回一个 collection,它包含可能正等待获取此锁的线程。
protected Collection<Thread> getQueuedThreads()
// 返回正等待获取此锁的线程估计数。
int getQueueLength()
// 返回一个 collection,它包含可能正在等待与此锁相关给定条件的那些线程。
protected Collection<Thread> getWaitingThreads(Condition condition)
// 返回等待与此锁相关的给定条件的线程估计数。
int getWaitQueueLength(Condition condition)
// 查询给定线程是否正在等待获取此锁。
boolean hasQueuedThread(Thread thread)
// 查询是否有些线程正在等待获取此锁。
boolean hasQueuedThreads()
// 查询是否有些线程正在等待与此锁有关的给定条件。
boolean hasWaiters(Condition condition)
// 如果是“公平锁”返回true,否则返回false。
boolean isFair()
// 查询当前线程是否保持此锁。
boolean isHeldByCurrentThread()
// 查询此锁是否由任意线程保持。
boolean isLocked()
// 获取锁。
void lock()
// 如果当前线程未被中断,则获取锁。
void lockInterruptibly()
// 返回用来与此 Lock 实例一起使用的 Condition 实例。
Condition newCondition()
// 仅在调用时锁未被另一个线程保持的情况下,才获取该锁。
boolean tryLock()
// 如果锁在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁。
boolean tryLock(long timeout, TimeUnit unit)
// 试图释放此锁。
void unlock()

Condition 函数列表

public interface Condition {
     //使当前线程加入 await() 等待队列中,并释放当锁,当其他线程调用signal()会重新请求锁。与Object.wait()类似。
    void await() throws InterruptedException;

    //调用该方法的前提是,当前线程已经成功获得与该条件对象绑定的重入锁,否则调用该方法时会抛出IllegalMonitorStateException。
    //调用该方法后,结束等待的唯一方法是其它线程调用该条件对象的signal()或signalALL()方法。等待过程中如果当前线程被中断,该方法仍然会继续等待,同时保留该线程的中断状态。 
    void awaitUninterruptibly();

    // 调用该方法的前提是,当前线程已经成功获得与该条件对象绑定的重入锁,否则调用该方法时会抛出IllegalMonitorStateException。
    //nanosTimeout指定该方法等待信号的的最大时间(单位为纳秒)。若指定时间内收到signal()或signalALL()则返回nanosTimeout减去已经等待的时间;
    //若指定时间内有其它线程中断该线程,则抛出InterruptedException并清除当前线程的打断状态;若指定时间内未收到通知,则返回0或负数。 
    long awaitNanos(long nanosTimeout) throws InterruptedException;

    //与await()基本一致,唯一不同点在于,指定时间之内没有收到signal()或signalALL()信号或者线程中断时该方法会返回false;其它情况返回true。
    boolean await(long time, TimeUnit unit) throws InterruptedException;

   //适用条件与行为与awaitNanos(long nanosTimeout)完全一样,唯一不同点在于它不是等待指定时间,而是等待由参数指定的某一时刻。
    boolean awaitUntil(Date deadline) throws InterruptedException;
    
    //唤醒一个在 await()等待队列中的线程。与Object.notify()相似
    void signal();

   //唤醒 await()等待队列中所有的线程。与object.notifyAll()相似
    void signalAll();
}

2.Condition的作用

参考博文2
synchronized与wait()和nitofy()/notifyAll()方法相结合可以实现等待/通知模型,ReentrantLock同样可以,但是需要借助Condition,且Condition有更好的灵活性,具体体现在:

  • 1.一个Lock里面可以创建多个Condition实例,实现多路通知
  • 2、notify()方法进行通知时,被通知的线程时Java虚拟机随机选择的,但是ReentrantLock结合Condition可以实现有选择性地通知,这是非常重要的。
    看一下利用Condition实现等待/通知模型的最简单用法,下面的代码注意一下,await()和signal()之前,必须要先lock()获得锁,使用完毕在finally中unlock()释放锁,这和wait()/notify()/notifyAll()使用前必须先获得对象锁是一样的:

3.使用

public class ThreadDomain40
{
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
    
    public void await()
    {
        try
        {
            lock.lock();
            System.out.println("await时间为:" + System.currentTimeMillis());
            condition.await();
            System.out.println("await等待结束");
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
        finally
        {
            lock.unlock();
        }
    }
    
    public void signal()
    {
        try
        {
            lock.lock();
            System.out.println("signal时间为:" + System.currentTimeMillis());
            condition.signal();
        }
        finally
        {
            lock.unlock();
        }
    }
}
public class MyThread40 extends Thread
{
    private ThreadDomain40 td;
    
    public MyThread40(ThreadDomain40 td)
    {
        this.td = td;
    }
    
    public void run()
    {
        td.await();
    }
}
public static void main(String[] args) throws Exception
{
    ThreadDomain40 td = new ThreadDomain40();
    MyThread40 mt = new MyThread40(td);
    mt.start();
    Thread.sleep(3000);
    td.signal();
}

看一下运行结果:

await时间为:1443970329524
signal时间为:1443970332524
await等待结束

差值是3000毫秒也就是3秒,符合代码预期,成功利用ReentrantLock的Condition实现了等待/通知模型。其实这个例子还证明了一点,Condition的await()方法是释放锁的,原因也很简单,要是await()方法不释放锁,那么signal()方法又怎么能调用到Condition的signal()方法呢?

注意要是用一个Condition的话,那么多个线程被该Condition给await()后,调用Condition的signalAll()方法唤醒的是所有的线程。如果想单独唤醒部分线程该怎么办呢?new出多个Condition就可以了,这样也有助于提升程序运行的效率。使用多个Condition的场景是很常见的,像ArrayBlockingQueue里就有。

补充2:

public class MyService {

        private Lock lock = new ReentrantLock();

        public Condition conditionA = lock.newCondition();

        public Condition conditionB = lock.newCondition();


        public void awaitA() {

            try{

                lock.lock();

                System.out.println("beginawaitA时间为" +System.currentTimeMillis()

                        +" ThreadName=" + Thread.currentThread().getName());

                conditionA.await();

                System.out.println("  end awaitA时间为" + System.currentTimeMillis()

                        +" ThreadName=" + Thread.currentThread().getName());

            }catch (InterruptedException e) {

                e.printStackTrace();

            }finally {

                lock.unlock();

            }

        }


        public void awaitB() {

            try{

                lock.lock();

                System.out.println("beginawaitB时间为" +System.currentTimeMillis()

                        +" ThreadName=" + Thread.currentThread().getName());

                conditionB.await();

                System.out.println("  end awaitB时间为" + System.currentTimeMillis()

                        +" ThreadName=" + Thread.currentThread().getName());

            }catch (InterruptedException e) {

                e.printStackTrace();

            }finally {

                lock.unlock();

            }

        }



        public void signalAll_A() {

            try{

                lock.lock();

                System.out.println("  signalAll_A时间为" + System.currentTimeMillis()

                        +" ThreadName=" + Thread.currentThread().getName());

                conditionA.signalAll();

            }finally {

                lock.unlock();

            }

        }



        public void signalAll_B() {

            try{

                lock.lock();

                System.out.println("  signalAll_B时间为" + System.currentTimeMillis()

                        +" ThreadName=" + Thread.currentThread().getName());

                conditionB.signalAll();

            }finally {

                lock.unlock();

            }

        }

        public static class ThreadA extends Thread {
            private MyService service;

            public ThreadA(MyService service) {

                super();

                this.service= service;

            }



            @Override

            public void run() {

                service.awaitA();

            }

        }

        public static class ThreadB extends Thread {

            private MyService service;
            public ThreadB(MyService service) {
                super();

                this.service= service;

            }

            @Override

            public void run() {

                service.awaitB();

            }

        }



            public static void main(String[] args) throws InterruptedException {

                MyService service = new MyService();

                ThreadA a = new ThreadA(service);

                a.setName("A");

                a.start();

                ThreadB b = new ThreadB(service);

                b.setName("B");

                b.start();

                Thread.sleep(3000);

                service.signalAll_A();

            }


}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值