ReentrantLock(排他锁)

ReentrantLock源码

https://www.cnblogs.com/LQBlog/p/15206866.html

简单demo

在多线程操作时。保证一块共享资源的原子性。第一想到的就是用synchronized关键字

在jdk5提供一个更灵活更强大的 ReentrantLock 

使用reentrantLock.lock();获得锁  使用reentrantLock.unlock();释放锁

public class ReentrantLockTest {
    ReentrantLock reentrantLock = new ReentrantLock();

    public void add(Object data) throws InterruptedException {
        try {
            reentrantLock.lock();
            System.out.println("模拟新增耗时");
            Thread.sleep(2000);
            System.out.println("新增完毕");
        } finally {
            // TODO: handle finally clause
            reentrantLock.unlock();
        }

    }

    public void get() throws InterruptedException {
        
        try {
            reentrantLock.lock();
            System.out.println("模拟获取");
            Thread.sleep(1000);
            System.out.println("新增完毕");
        } finally {
            // TODO: handle finally clause
            reentrantLock.unlock();
        }
    }
    public static void main(String[] args) {
        final ReentrantLockTest reentrantLockTest=new ReentrantLockTest();
        new Thread(new Runnable() {
            
            @Override
            public void run() {
                // TODO Auto-generated method stub
                try {
                    reentrantLockTest.add(1);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }).start();
        new Thread(new Runnable() {
            
            @Override
            public void run() {
                // TODO Auto-generated method stub
                try {
                    reentrantLockTest.get();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }).start();;
    }

synchronized与ReentrantLock区别

1.synchronized是交给jvm来调度的。ReentrantLock是通过java代码控制的

2.在synchronized在很多线程竞争的时候会使性能大大下降ReentrantLock在很多线程竞争是不会

3.ReentrantLock必须配合finally 否则容易产生死锁

ReentrantLock reentrantLock = new ReentrantLock();

    public void Test1() {
        reentrantLock.lock();
        /*
         * 执行逻辑
        */
        Test2();
    }
    public void Test2() {
        reentrantLock.unlock();
    }

5.ReentrantLock可以进行公平锁选择

什么情况下选用ReentrantLock

1.某个线程在等待一个锁的控制权的这段时间需要中断 tryLock

public class ReentrantLockTest {
    ReentrantLock reentrantLock = new ReentrantLock();

    public void add(Object data) throws InterruptedException {
        try {
            reentrantLock.lock();
            
            Thread.sleep(10000);
            System.out.println("模拟新增耗时");
        
        } finally {
            // TODO: handle finally clause
            reentrantLock.unlock();
        }

    }

    public void get() throws InterruptedException {
        
        try {
            reentrantLock.tryLock(1000, TimeUnit.MILLISECONDS);//尝试获得锁1000毫秒 获取不到放弃
            System.out.println("模拟获取");
            Thread.sleep(1000);
            System.out.println("获取完毕");
        } finally {
            // TODO: handle finally clause
            reentrantLock.unlock();
        }
    }
    public static void main(String[] args) {
        final ReentrantLockTest reentrantLockTest=new ReentrantLockTest();
        new Thread(new Runnable() {
            
            @Override
            public void run() {
                // TODO Auto-generated method stub
                try {
                    reentrantLockTest.add(1);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }).start();
        new Thread(new Runnable() {
            
            @Override
            public void run() {
                // TODO Auto-generated method stub
                try {
                    reentrantLockTest.get();
                
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println("执行其他业务逻辑");
            }
        },"t2").start();;
    }
}

第一个线程获取锁 等待5秒。当reentrantLock.tryLock(1000, TimeUnit.MILLISECONDS) 会尝试获得锁 若果1秒之内没获取 抛出异常 继续往下执行

打印

模拟获取
获取完毕Exception in thread "t2" 
java.lang.IllegalMonitorStateException
    at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(Unknown Source)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(Unknown Source)
    at java.util.concurrent.locks.ReentrantLock.unlock(Unknown Source)
    at com.bjsxt.height.concurrent019.ReentrantLockTest.get(ReentrantLockTest.java:32)
    at com.bjsxt.height.concurrent019.ReentrantLockTest$2.run(ReentrantLockTest.java:56)
    at java.lang.Thread.run(Unknown Source)
模拟新增耗时

 


2.需要分开处理一些wait-notify,ReentrantLock里面的Condition应用,能够控制notify哪个线程 

public static void main(String[] args) throws InterruptedException {
        final ReentrantLock reentrantLock = new ReentrantLock();
        final Condition condition1= reentrantLock.newCondition();
        new Thread(new Runnable() {
            
            @Override
            public void run() {
                // TODO Auto-generated method stub
                try {
                    reentrantLock.lock();
                    condition1.await();
                    System.out.println("线程1往下执行");
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }finally {
                    reentrantLock.unlock();
                }
            }
        }).start();
        new Thread(new Runnable() {
            
            @Override
            public void run() {
                // TODO Auto-generated method stub
                try {
                    reentrantLock.lock();
                    Thread.sleep(5000);
                    condition1.signal();
                    
            
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }finally {
                    reentrantLock.unlock();
                }
            }
        },"t2").start();
        Thread.sleep(2000);
        //取消 condition1等待
    }
 reentrantLock.newCondition()可以new多个 。可以通过reentrantLock.signalAll()唤醒所有等待的condition


3.具有公平锁功能,每个到来的线程都将排队等候

ReentrantLock reentrantLock = new ReentrantLock(true) 则为公平锁

ReentrantLock与synchronized区别

1.从底层实现synchronized是JVM层面的,Reentrantlock是应用层面
2.synchronized是通过jvm 的monitor指令实现加锁和释放锁,Reentrantlock是在应用上基于AQS实现+CAS实现
3.synchronized能够保证线程的原子性、可见性、有序性、可重入性。Reentrantlock只能保证 原子性,和可重入性。如果需要保证可见性需要加volatile关键字。
4.在jdk1.6之前Reentrantlock的性能优于synchronized,因为synchronized全部都是重量级锁 直接参与竞争,在jdk1.6之后进行了优化通过锁升级(偏向锁 轻量级锁 重量级锁)锁粗化 锁消除 的优化方式,锁升级 本质在以前mointor锁直接参与竞争获取 优化前面增加应用层面的CAS判断 减少直接参与竞争
5.jdk1.6之后更推荐使用synchronized




posted @ 2018-05-03 21:28  意犹未尽  阅读(404)  评论(0编辑  收藏  举报