zoukankan      html  css  js  c++  java
  • ReadWriteLock: 读写锁

    ReadWriteLock: 读写锁

    ReadWriteLock:

    JDK1.5提供的读写分离锁,采用读写锁分离可以有效帮助减少锁竞争。

    特点:

    1).使用读写锁。当线程只进行读操作时,可以允许多个线程同时读

    2).写写操作,读写操作间依然需要相互等待和持有锁。

    一).使用读写锁与使用重入锁进行读读写操作

    开启200个线程,测试读写锁和重入锁的读效率。

    使用重入锁进行读写操作:ReentrantLock_Rw

    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     * 使用重入锁进行读写操作
     *    线程的读写使用同一把锁。
     */
    public class ReentrantLock_RW {
        private static ReentrantLock lock = new ReentrantLock();
        private static int value ;
    
        //读操作
        public Object handleRead() throws InterruptedException {
            try {
                //获取锁
                lock.lock();
                //模拟读操作,读操作耗时越多,读写锁的优势越明显
                Thread.sleep(1);
                return value;
            }finally {
                lock.unlock();
            }
        }
        /**
         * 写操作
         */
        public void handleWrite(int i) throws InterruptedException {
            try {
                lock.lock();
                //模拟写操作
                Thread.sleep(1);
                value = i;
            }finally {
                lock.unlock();
            }
        }
    }
    
    

    使用ReadWriteLock进行读写操作: ReadWriteLock_RW

    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    /**
     * 使用ReadWriteLock进行读写操作
     */
    public class ReadWriteLock_RW {
        private static int value;
        private static ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    
    
        /**
                * 读取锁
        */
        private static Lock readLock = readWriteLock.readLock();
    
        /**
         * 写入锁
         */
        private static Lock writeLock = readWriteLock.writeLock();
    
        /**
         * 读操作
         */
        public Object handleRead() throws InterruptedException {
            try {
                readLock.lock();
                Thread.sleep(1);
                return value;
            }finally {
                //释放锁
                readLock.unlock();
            }
    
        }
    
        /**
         * 写操作
         */
        public void handleWrite(int index) throws InterruptedException {
            try{
                //获取锁
                writeLock.lock();
                Thread.sleep(1);
                value = index;
            }finally {
                //释放锁
                writeLock.unlock();
            }
        }
    
    }
    
    

    二)、测试多线程运行时间的知识储备

    参考:https://www.cnblogs.com/jack-xsh/p/8615644.html

    怎么测试多线程的运行时间?

    //指定要开启的线程数
    final static CountdownLatch countdownLatch = new CountdownLatch(200);
    
    //每执行完一个线程,countdownLatch的线程数减一。
    countdownLatch.countdown();
    
    //挂起主线程,当cuntdown()的线程数为0,恢复主线程。
    countdownLatch.await();
    

    三)、使用重入锁进行读操作性能测试

    重入锁读操作线程:ReentrantLockReadThread

    **
     * 比较重入锁与读写锁读数据的性能
     */
    public class ReentrantLockReadThread implements Runnable{
        //闭锁,线程计时工具
        private CountDownLatch countDownLatch;
        private  ReentrantLock_RW reentrantLockRw;
        public ReentrantLockReadThread(ReentrantLock_RW reentrantLockRw, CountDownLatch countDownLatch) {
            this.reentrantLockRw = reentrantLockRw;
            this.countDownLatch = countDownLatch;
        }
    
        @Override
        public void run() {
            try {
                reentrantLockRw.handleRead();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                //线程执行完将线程挂起
                countDownLatch.countDown();
            }
        }
    }
    
    

    重入锁读线程效率:ReentrantLockReadThreadTest

    public class ReentrantLockReadThreadTest {
        //程序计计时器,用于计算多线程的执行时间
        final static CountDownLatch countDownLatch = new CountDownLatch(200);
        //其实开启200个线程读取lock中值的速率
        public static void main(String[] args) throws InterruptedException {
            ReentrantLock_RW reentrantLockRw = new ReentrantLock_RW();
            ReentrantLockReadThread readThread = new ReentrantLockReadThread(reentrantLockRw, countDownLatch);
            long time = System.currentTimeMillis();
            for(int i = 0; i < 200; i++){
                Thread t = new Thread(readThread);
                t.start();
            }
            //将主线程挂起
            countDownLatch.await();
            System.out.println(System.currentTimeMillis() - time);
        }
    }
    

    结果:

    2194
    

    四)、使用读写锁进行读操作的性能测试

    读写锁读操作线程:ReadLockThread

    import java.util.concurrent.CountDownLatch;
    
    /**
     * 读入锁线程
     */
    public class ReadLockThread implements Runnable{
        private ReadWriteLock_RW readWriteLockrw;
        private CountDownLatch countDownLatch;
        public ReadLockThread(ReadWriteLock_RW readWriteLockrw, CountDownLatch countDownLatch) {
            this.readWriteLockrw = readWriteLockrw;
            this.countDownLatch = countDownLatch;
        }
    
        @Override
        public void run() {
            try {
                readWriteLockrw.handleRead();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                //线程执行完将该线程挂起
                countDownLatch.countDown();
            }
        }
    }
    
    

    读线程读写效率测试:ReadLockThreadTest

    import java.util.concurrent.CountDownLatch;
    
    /**
     * 测试使用ReadLock的性能
     */
    public class ReadLockThreadTest {
        final static CountDownLatch countDownLatch = new CountDownLatch(200);
        public static void main(String[] args) throws InterruptedException {
            ReadWriteLock_RW readWriteLockRw = new ReadWriteLock_RW();
            ReadLockThread readThread = new ReadLockThread(readWriteLockRw, countDownLatch);
            long time = System.currentTimeMillis();
            for(int i = 0; i < 200; i++){
                Thread t = new Thread(readThread);
                t.start();
            }
            countDownLatch.await();  //一定要等到countDown()方法执行完毕后才使用,将主线程挂起
            System.out.println(System.currentTimeMillis() - time);
        }
    }
    

    结果

    26
    

    结论:使用读写锁来对数据进行读取,效率远远高于重入锁。

    五)、使用重入锁进行写操作的性能比较

    重入锁写操作线程:ReentrantLockWriteThread

    public class ReentrantLockWriteThread implements Runnable {
        private CountDownLatch countDownLatch;
        private ReentrantLock_RW reentrantLockRw;
    
        public ReentrantLockWriteThread(ReentrantLock_RW reentrantLockRw, CountDownLatch countDownLatch) {
            this.countDownLatch = countDownLatch;
            this.reentrantLockRw = reentrantLockRw;
        }
    
        @Override
        public void run() {
            try {
                reentrantLockRw.handleWrite(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                //线程执行完,线程数减一
                countDownLatch.countDown();
            }
        }
    }
    
    

    写线程效率测试:ReentrantLockWriteThreadTest

    public class ReentrantLockWriteThreadTest {
        final static CountDownLatch countDownLatch =  new CountDownLatch(200);
        public static void main(String[] args) throws InterruptedException {
            ReentrantLock_RW reentrantLockRw = new ReentrantLock_RW();
            long start = System.currentTimeMillis();
            for(int i = 0; i < 200; i++){
                Thread t = new Thread(new ReentrantLockWriteThread(reentrantLockRw, countDownLatch));
                t.start();
            }
            countDownLatch.await();
            System.out.println(System.currentTimeMillis() - start);
        }
    }
    

    结果:

    408
    

    六)、使用读写锁进行写操作性能比较

    读写锁写操作线程: WriteLockThread

    public class WriteLockThread implements Runnable{
        private ReadWriteLock_RW readWriteLockrw;
        private CountDownLatch countDownLatch;
        public WriteLockThread(ReadWriteLock_RW readWriteLockrw, CountDownLatch countDownLatch) {
            this.readWriteLockrw = readWriteLockrw;
            this.countDownLatch = countDownLatch;
        }
    
        @Override
        public void run() {
            try {
                readWriteLockrw.handleWrite(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                //线程执行完将该线程挂起
                countDownLatch.countDown();
            }
        }
    }
    

    写线程效率测试:WriteLockThreadTest

    public class WriteLockThread implements Runnable{
        private ReadWriteLock_RW readWriteLockrw;
        private CountDownLatch countDownLatch;
        public WriteLockThread(ReadWriteLock_RW readWriteLockrw, CountDownLatch countDownLatch) {
            this.readWriteLockrw = readWriteLockrw;
            this.countDownLatch = countDownLatch;
        }
    
        @Override
        public void run() {
            try {
                readWriteLockrw.handleWrite(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                //线程执行完将该线程挂起
                countDownLatch.countDown();
            }
        }
    }
    

    结果:

    398
    

    结论:使用读写锁和重入锁进行写操作的速率大致相同。

    ​ 在读多写少的场合,使用读写锁可以分离读操作和写操作,使所有读操作间

    ​ 真正的并行。

    使用场景:当线程使用读写操作共享数据时,使用读写锁,可以减少读线程的等待

    ​ 时间提高系统的并发能力。

    金麟岂能忍一世平凡 飞上了青天 天下还依然
  • 相关阅读:
    JVM概论
    设计模式之工厂模式
    Java基础之多线程简述
    设计模式之单例模式
    设计模式之模板方法模式
    设计模式之适配器模式
    设计模式之策略模式
    机器学习浅析之最优解问题(二)
    MapReduce架构与生命周期
    Hadoop系列之实验环境搭建
  • 原文地址:https://www.cnblogs.com/Auge/p/11763290.html
Copyright © 2011-2022 走看看