美文网首页Java 杂谈
Java并发锁之ReentrantLock和ReentrantR

Java并发锁之ReentrantLock和ReentrantR

作者: LandHu | 来源:发表于2018-12-08 13:29 被阅读0次

    锁类型:

    可重入锁:在执行对象中所有同步方法不用再次获得锁
    可中断锁:在等待获取锁过程中可中断
    公平锁: 按等待获取锁的线程的等待时间进行获取,等待时间长的具有优先获取锁权利
    读写锁:对资源读取和写入的时候拆分为2部分处理,读的时候可以多线程一起读,写的时候必须同步地写

    Lock主要方法:

    lock():获取锁,如果锁被暂用则一直等待
    unlock():释放锁
    tryLock(): 注意返回类型是boolean,如果获取锁的时候锁被占用就返回false,否则返回true
    tryLock(long time, TimeUnit unit):比起tryLock()就是给了一个时间期限,保证等待参数时间
    lockInterruptibly():用该锁的获得方式,如果线程在获取锁的阶段进入了等待,那么可以中断此线程,先去做别的事

    ReentrantLock:

    lock()样例:

    public class LockTest {
        private Lock lock = new ReentrantLock();
    
        //需要参与同步的方法
        private void method(Thread thread){
            lock.lock();
            try {
                System.out.println("线程名"+thread.getName() + "获得了锁");
            }catch(Exception e){
                e.printStackTrace();
            } finally {
                System.out.println("线程名"+thread.getName() + "释放了锁");
                lock.unlock();
            }
        }
    
        public static void main(String[] args) {
            LockTest lockTest = new LockTest();
    
            //线程1
            Thread t1 = new Thread(new Runnable() {
    
                @Override
                public void run() {
                    lockTest.method(Thread.currentThread());
                }
            }, "t1");
    
            Thread t2 = new Thread(new Runnable() {
    
                @Override
                public void run() {
                    lockTest.method(Thread.currentThread());
                }
            }, "t2");
    
            t1.start();
            t2.start();
        }
    }
    //执行情况:线程名t1获得了锁
    //         线程名t1释放了锁
    //         线程名t2获得了锁
    //         线程名t2释放了锁
    

    tryLock()样例:

    public class LockTest {
        private Lock lock = new ReentrantLock();
    
        //需要参与同步的方法
        private void method(Thread thread){
    /*      lock.lock();
            try {
                System.out.println("线程名"+thread.getName() + "获得了锁");
            }catch(Exception e){
                e.printStackTrace();
            } finally {
                System.out.println("线程名"+thread.getName() + "释放了锁");
                lock.unlock();
            }*/
    
    
            if(lock.tryLock()){
                try {
                    System.out.println("线程名"+thread.getName() + "获得了锁");
                }catch(Exception e){
                    e.printStackTrace();
                } finally {
                    System.out.println("线程名"+thread.getName() + "释放了锁");
                    lock.unlock();
                }
            }else{
                System.out.println("我是"+Thread.currentThread().getName()+"有人占着锁,我就不要啦");
            }
        }
    
        public static void main(String[] args) {
            LockTest lockTest = new LockTest();
    
            //线程1
            Thread t1 = new Thread(new Runnable() {
    
                @Override
                public void run() {
                    lockTest.method(Thread.currentThread());
                }
            }, "t1");
    
            Thread t2 = new Thread(new Runnable() {
    
                @Override
                public void run() {
                    lockTest.method(Thread.currentThread());
                }
            }, "t2");
    
            t1.start();
            t2.start();
        }
    }
    //执行结果: 线程名t2获得了锁
    //         我是t1有人占着锁,我就不要啦
    //         线程名t2释放了锁
    

    使用Lock时可以使用新的等待/通知类Condition,Condition一定是针对某一把固定的锁,也就是说,只有在有锁的基础上才会产生Condition
    Condition样例:

    public class UseCondition {
    
        private Lock lock = new ReentrantLock();
        private Condition condition = lock.newCondition();
    
        public void method1(){
            try {
                lock.lock();
                System.out.println("当前线程:" + Thread.currentThread().getName() + "进入等待状态..");
                Thread.sleep(3000);
                System.out.println("当前线程:" + Thread.currentThread().getName() + "释放锁..");
                //释放锁,类似于 Object wait,阻塞于此
                condition.await();
                System.out.println("当前线程:" + Thread.currentThread().getName() +"继续执行...");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    
        public void method2(){
            try {
                lock.lock();
                System.out.println("当前线程:" + Thread.currentThread().getName() + "进入..");
                Thread.sleep(3000);
                System.out.println("当前线程:" + Thread.currentThread().getName() + "发出唤醒..");
                //不释放锁类,似于Object notify
                condition.signal();
                System.out.println("当前线程:" + Thread.currentThread().getName() + "没有释放锁");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    
        public static void main(String[] args) {
    
            final UseCondition uc = new UseCondition();
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    uc.method1();
                }
            }, "t1");
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    uc.method2();
                }
            }, "t2");
            t1.start();
    
            t2.start();
        }
    }
    

    实现原理:ReentrantLock 实现原理

    ReentrantReadWriteLock:

    读写锁的机制本质上分为两把锁,读锁和写锁,在读锁情况下,多个线程可以并发访问资源,只有当是写锁时只能一个一个的顺序执行。
    读读共享,写写互斥,读写互斥

    public class UseReentrantReadWriteLock {
        private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
        private ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();
        private ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();
    
        public void read() {
            try {
                readLock.lock();
                System.out.println("当前线程:" + Thread.currentThread().getName() + "进入...");
                Thread.sleep(3000);
                System.out.println("当前线程:" + Thread.currentThread().getName() + "退出...");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                readLock.unlock();
            }
        }
    
        public void write() {
            try {
                writeLock.lock();
                System.out.println("当前线程:" + Thread.currentThread().getName() + "进入...");
                Thread.sleep(3000);
                System.out.println("当前线程:" + Thread.currentThread().getName() + "退出...");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                writeLock.unlock();
            }
        }
    
        public static void main(String[] args) {
    
            final UseReentrantReadWriteLock urrw = new UseReentrantReadWriteLock();
    
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    urrw.read();
                }
            }, "t1");
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    urrw.read();
                }
            }, "t2");
            Thread t3 = new Thread(new Runnable() {
                @Override
                public void run() {
                    urrw.write();
                }
            }, "t3");
            Thread t4 = new Thread(new Runnable() {
                @Override
                public void run() {
                    urrw.write();
                }
            }, "t4");
            t1.start();
            t2.start();
            //      t1.start(); // R
            //      t3.start(); // W
            t3.start();
            t4.start();
        }
    }
    

    实现原理:轻松掌握java读写锁(ReentrantReadWriteLock)的实现原理

    参考:Java并发之重入锁+读写锁


    技术讨论 & 疑问建议 & 个人博客

    版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 许可协议,转载请注明出处!

    相关文章

      网友评论

        本文标题:Java并发锁之ReentrantLock和ReentrantR

        本文链接:https://www.haomeiwen.com/subject/kplacqtx.html