ReentrantLock显示锁

前言:

synchronized和ReentrantLock同为锁机制,synchronized内置锁为同步锁的首选。而显示锁ReentrantLock,它并不是用来替代synchronized的,而是作为内置锁不适用时另一种可选择的高级功能。 


什么情况下使用ReentrantLock,这里不列详细的原理,只列比较容易理解的地方:

1、竞争资源激烈时用ReentrantLock,反之用synchronized;
  • 竞争资源不激烈的情况下,synchronized的性能较高,synchronized机制属于轻量级,对于只有少数线程中运行成本较低,而ReentrantLock相反。
  • 竞争资源激烈的情况下,ReentrantLock的性能较高,因为synchronized属于线程独占锁,比如A已经获得了该锁,B也想获得该锁就只有依靠阻塞来等待,直到A成功释放掉该锁(容易出现死锁),此时还有个操作就是CPU不断的在A和B之间切换,一旦还有CDEF等等若干个线程和B同一种情况,可想而知CPU在上下文切换上会浪费很多精力。而ReentrantLock锁的方式可以很好的优化这一问题。它的工作机制是如果A被锁住,BCDEF等线程试图获取该锁,一段时间后发现获取不到,它们可以中断自己,之后CPU不会再切换到这些线程而是专心去执行A的任务。所以在竞争激烈的情况下ReentrantLock更加有优势。(简单说就是JVM花更少的时间来调度,更多的时间来执行)
2、需要手动控制线程的中断、唤起等操作。
     因为ReentrantLock为显示锁,即可调用lock()/unlock()等方法进行操作,虽跟synchronized内建型锁相比代码缺乏优雅性,但和Condition相互配合操作性更加灵活。 


下面一个简单的Demo。
逻辑是实现一个简单的生产者和消费者模式的例子:
提一个简单的问题,让我们带着问题参考代码。
PS:这里为了代码的简介(懒),就拿Int型对象mQueue代替队列对象,请把mQueue想象成队列对象。。 

启动程序
public static void main(String[] args) {
    TestReentrantLock testReentrantLock = new TestReentrantLock();
    testReentrantLock.startTest();
}

下面为TestReentrantLock.java代码
public class TestReentrantLock {

    ReentrantLock reentrantLock = new ReentrantLock();
    Condition condition = reentrantLock.newCondition();
    int mQueue = 0;

    public void startTest() {
        newThread();
        producer();
    }

    public void newThread() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                consumer();
            }
        }).start();
    }

    public void consumer() {
        reentrantLock.lock();
        if (reentrantLock.isLocked()){
            System.out.println("\nConsumer gets the lock\n");
        }
        try {
            while (mQueue == 0) {
                System.out.println("The thread is waiting for consumers.\n");
                condition.await();
                System.out.println("The thread is starting for consumers.\n");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            reentrantLock.unlock();
            if (!reentrantLock.isLocked()){
                System.out.println("Consumer releases the lock\n");
            }
        }
        System.out.println("Done");
    }

    public void producer() {
        try {
            Thread.sleep(1000);
            reentrantLock.lock();
            Thread.sleep(5000);
            mQueue++;
            System.out.println("Producer add content\n");
            condition.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            reentrantLock.unlock();
            if (!reentrantLock.isLocked()){
                System.out.println("Producer releases the lock\n");
            }
        }
    }
}

1、创建一个线程,用ReentrantLock对象锁住,获取mQueue队列中的内容,如果有内容完成操作,如果没有内容则利用Condition对象中断线程,当Condition对象调用await()方法后会调用native方法自动解锁。
2、在新线程获取内容为空之后,主线程的producer()方法才执行,用ReentrantLock对象锁住,给mQueue添加内容,利用Condition对象调用signal()方法唤起新线程。
3、被唤起被中断的新线程,从被中断的代码继续向下执行,如果符合while()条件里面则重复执行其中的代码,不符合条件则跳出while()向下执行。




你可能感兴趣的:(扎实的Java基础)