ReentrantLock及Condition

ReentrantLock      

        ReentrantLock,一个可重入的互斥锁,它具有与使用synchronized方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大。

Condition介绍

          Condition是一个多线程间协调通信的工具类,使得某个或者某些线程一起等待某个条件(Condition),只有当该条件具备( signal 或者 signalAll方法被带调用)时 ,这些等待线程才会被唤醒,从而重新争夺锁。

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

        1. Object的wait、notify、notifyAll 需要与synchronized配合使用,Condition 的 await、signal、signalAll 需要与显式锁Lock配合使用,调用await、signal、signalAll方法都必须在lock 保护之内。

        2. 和Object的wait方法一样,await在进入等待队列后会释放锁和cpu,当被其他线程唤醒或者超时或中断后都需要重新获取锁,获取锁后才会从await方法中退出。

        3. Condition的await提供了比wait更加强大的机制,譬如提供了可中断或者不可中断的await机制等。

        4. 一个ReentrantLock里面可以创建多个Condition实例,实现多路通知。

        5. notify()方法进行通知时,被通知的线程时Java虚拟机随机选择的,但是ReentrantLock结合Condition可以实现有选择性地通知,这是非常重要的。

        Condition实现等待/通知模型的最简单用法,下面的代码注意一下,await()和signal()之前,必须要先lock()获得锁,使用完毕在finally中unlock()释放锁,这和wait()/notify()/notifyAll()使用前必须先获得对象锁是一样的。

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里就有。

参考文档:

ReentrantLock和Condition理解及应用 - 简书

Java多线程11:ReentrantLock的使用和Condition - 五月的仓颉 - 博客园

你可能感兴趣的:(java并发,p2p,wpf,tv)