zoukankan      html  css  js  c++  java
  • ReentrantReadWriteLock读写锁的使用

      类ReentrantLock具有完全互斥排他的效果,即同一时间只有一个线程在执行ReentrantLock.lock()后面的代码。这样虽然保证了线程的安全性,但是效率低下。JDK提供了ReentrantReadWriteLock读写锁,使用它可以加快效率,在某些不需要操作实例变量的方法中,完全可以使用读写锁ReemtrantReadWriteLock来提升该方法的运行速度。

      读写锁表示有两个锁,一个是读操作相关的锁,也称为共享锁;另一个是写操作相关的锁,也叫排他锁。也就是多个读锁之间不互斥,读锁与写锁互斥、写锁与写锁互斥。在没有线程Thread进行写入操作时,进行读取操作的多个Thread都可以获取读锁,而进行写入操作的Thread只有在获取写锁后才能进行写入操作。即多个Thread可以同时进行读取操作,但是同一时刻只允许一个Thread进行写入操作。

    1.读读共享

      读锁与读锁可以共享,这种锁一般用于只读操作,不对变量进行修改操作。

    package cn.qlq.thread.twelve;
    
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import cn.qlq.thread.one.RunnableThread;
    
    public class Demo1 {
        private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();// 读写锁
        private static final Logger log = LoggerFactory.getLogger(Demo1.class);
    
        private int i;
    
        public String readI() {
            try {
                lock.readLock().lock();// 占用读锁
                log.info("threadName -> {} 占用读锁,i->{}", Thread.currentThread().getName(), i);
                Thread.sleep(2 * 1000);
            } catch (InterruptedException e) {
    
            } finally {
                log.info("threadName -> {} 释放读锁,i->{}", Thread.currentThread().getName(), i);
                lock.readLock().unlock();// 释放读锁
            }
            return i + "";
        }
    
        public static void main(String[] args) {
            final Demo1 demo1 = new Demo1();
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    demo1.readI();
                }
            };
    
            new Thread(runnable, "t1").start();
            new Thread(runnable, "t2").start();
            new Thread(runnable, "t3").start();
    
        }
    
    }

    结果:

    18:27:20 [cn.qlq.thread.twelve.Demo1]-[INFO] threadName -> t2 占用读锁,i->0
    18:27:20 [cn.qlq.thread.twelve.Demo1]-[INFO] threadName -> t1 占用读锁,i->0
    18:27:20 [cn.qlq.thread.twelve.Demo1]-[INFO] threadName -> t3 占用读锁,i->0
    18:27:22 [cn.qlq.thread.twelve.Demo1]-[INFO] threadName -> t3 释放读锁,i->0
    18:27:22 [cn.qlq.thread.twelve.Demo1]-[INFO] threadName -> t1 释放读锁,i->0
    18:27:22 [cn.qlq.thread.twelve.Demo1]-[INFO] threadName -> t2 释放读锁,i->0

    2.写写互斥

      写锁与写锁互斥,这就类似于ReentrantLock的作用效果。

    package cn.qlq.thread.twelve;
    
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class Demo2 {
        private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();// 读写锁
        private static final Logger log = LoggerFactory.getLogger(Demo2.class);
    
        private int i;
    
        public void addI() {
            try {
                lock.writeLock().lock();// 占用写锁
                log.info("threadName -> {} 占用写锁,i->{}", Thread.currentThread().getName(), i);
                Thread.sleep(2 * 1000);
                i++;
            } catch (InterruptedException e) {
    
            } finally {
                log.info("threadName -> {} 释放写锁,i->{}", Thread.currentThread().getName(), i);
                lock.writeLock().unlock();// 释放写锁
            }
        }
    
        public static void main(String[] args) {
            final Demo2 demo1 = new Demo2();
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    demo1.addI();
                }
            };
    
            new Thread(runnable, "t1").start();
            new Thread(runnable, "t2").start();
            new Thread(runnable, "t3").start();
    
        }
    
    }

    结果:(从时间可以看出实现了互斥效果)

    18:31:31 [cn.qlq.thread.twelve.Demo2]-[INFO] threadName -> t1 占用写锁,i->0
    18:31:33 [cn.qlq.thread.twelve.Demo2]-[INFO] threadName -> t1 释放写锁,i->1
    18:31:33 [cn.qlq.thread.twelve.Demo2]-[INFO] threadName -> t2 占用写锁,i->1
    18:31:35 [cn.qlq.thread.twelve.Demo2]-[INFO] threadName -> t2 释放写锁,i->2
    18:31:35 [cn.qlq.thread.twelve.Demo2]-[INFO] threadName -> t3 占用写锁,i->2
    18:31:37 [cn.qlq.thread.twelve.Demo2]-[INFO] threadName -> t3 释放写锁,i->3

    3.读写互斥

    package cn.qlq.thread.twelve;
    
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    /**
     * 读写互斥
     * 
     * @author Administrator
     *
     */
    public class Demo3 {
        private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();// 读写锁
        private static final Logger log = LoggerFactory.getLogger(Demo3.class);
    
        private int i;
    
        public String readI() {
            try {
                lock.readLock().lock();// 占用读锁
                log.info("threadName -> {} 占用读锁,i->{}", Thread.currentThread().getName(), i);
                Thread.sleep(2 * 1000);
            } catch (InterruptedException e) {
    
            } finally {
                log.info("threadName -> {} 释放读锁,i->{}", Thread.currentThread().getName(), i);
                lock.readLock().unlock();// 释放读锁
            }
            return i + "";
        }
    
        public void addI() {
            try {
                lock.writeLock().lock();// 占用写锁
                log.info("threadName -> {} 占用写锁,i->{}", Thread.currentThread().getName(), i);
                Thread.sleep(2 * 1000);
                i++;
            } catch (InterruptedException e) {
    
            } finally {
                log.info("threadName -> {} 释放写锁,i->{}", Thread.currentThread().getName(), i);
                lock.writeLock().unlock();// 释放写锁
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            final Demo3 demo1 = new Demo3();
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    demo1.readI();
                }
            }, "t1").start();
    
            Thread.sleep(1 * 1000);
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    demo1.addI();
                }
            }, "t2").start();
    
        }
    
    }

    结果:

    18:34:59 [cn.qlq.thread.twelve.Demo3]-[INFO] threadName -> t1 占用读锁,i->0
    18:35:01 [cn.qlq.thread.twelve.Demo3]-[INFO] threadName -> t1 释放读锁,i->0
    18:35:01 [cn.qlq.thread.twelve.Demo3]-[INFO] threadName -> t2 占用写锁,i->0
    18:35:03 [cn.qlq.thread.twelve.Demo3]-[INFO] threadName -> t2 释放写锁,i->1

    4.写读互斥

      写锁与读锁也是互斥的。先占用写锁后读锁进行抢占也会等待写锁释放。

    package cn.qlq.thread.twelve;
    
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    /**
     * 读写互斥
     * 
     * @author Administrator
     *
     */
    public class Demo3 {
        private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();// 读写锁
        private static final Logger log = LoggerFactory.getLogger(Demo3.class);
    
        private int i;
    
        public String readI() {
            try {
                lock.readLock().lock();// 占用读锁
                log.info("threadName -> {} 占用读锁,i->{}", Thread.currentThread().getName(), i);
                Thread.sleep(2 * 1000);
            } catch (InterruptedException e) {
    
            } finally {
                log.info("threadName -> {} 释放读锁,i->{}", Thread.currentThread().getName(), i);
                lock.readLock().unlock();// 释放读锁
            }
            return i + "";
        }
    
        public void addI() {
            try {
                lock.writeLock().lock();// 占用写锁
                log.info("threadName -> {} 占用写锁,i->{}", Thread.currentThread().getName(), i);
                Thread.sleep(2 * 1000);
                i++;
            } catch (InterruptedException e) {
    
            } finally {
                log.info("threadName -> {} 释放写锁,i->{}", Thread.currentThread().getName(), i);
                lock.writeLock().unlock();// 释放写锁
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
            final Demo3 demo1 = new Demo3();
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    demo1.addI();
                }
            }, "t2").start();
    
            Thread.sleep(1 * 1000);
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    demo1.readI();
                }
            }, "t1").start();
        }
    
    }

    结果:

    18:36:14 [cn.qlq.thread.twelve.Demo3]-[INFO] threadName -> t2 占用写锁,i->0
    18:36:16 [cn.qlq.thread.twelve.Demo3]-[INFO] threadName -> t2 释放写锁,i->1
    18:36:16 [cn.qlq.thread.twelve.Demo3]-[INFO] threadName -> t1 占用读锁,i->1
    18:36:18 [cn.qlq.thread.twelve.Demo3]-[INFO] threadName -> t1 释放读锁,i->1

    总结: 读写、写读、写写都是互斥的,而读读是异步非互斥的。

          也就是只要有写锁的参与就会进行同步,所以写锁也被称为排他锁,读锁被称为共享锁。

  • 相关阅读:
    梯度下降的矩阵分解公式推导
    再谈矩阵分解在推荐系统中的应用
    浅谈矩阵分解在推荐系统中的应用
    tomcat局域网内发布html
    通过JavaScript动态生成html控件
    html 复选框checkbox
    HTML <frameset>不同frame之间传值
    OpenLayers 案例一
    ubuntu java开发环境jdk安装
    如何成为Python高手
  • 原文地址:https://www.cnblogs.com/qlqwjy/p/10158409.html
Copyright © 2011-2022 走看看