zoukankan      html  css  js  c++  java
  • java并发学习02---ReadWriteLock 读写锁

    同步器--读写锁

    java并发包中帮我们进行了一系列的封装,之前的重入锁需要我们手动的加锁和释放锁,而同步器只需要我们简单的去使用就可以了。

    之前我们无论是使用synchronized还是ReentrantLock,都是对整个操作进行了加锁,但我们可以想象到,如果两个线程都进行的知识读取的操作,那么实际上我们是不需要加锁的。

    而读写,包括写与写之间还是需要加锁的。

    而读写锁就是帮我们来做这件事情的,如果连续两次操作都是读的话,那么我们就不需要加锁了

    关于读写锁的具体原理笔者能力有限,暂时还无法给出自己的理解,这里给出一篇并发编程网的文章供大家参考

    java中的读写锁

    这里给出一个简单的例子,说明读写锁的使用:

    package thread.thread_util;
    
    import java.util.Random;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    /**
     * 展示读写锁的基本应用
     * 读读之间不加锁
     * 读写和写写之间才加锁
     */
    public class Lesson18_ReadWriteLock {
        private static Lock lock = new ReentrantLock();
        private static ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
        private static Lock readLock = rwLock.readLock();
        private static Lock writeLock = rwLock.writeLock();
        private int value = 1;
    
        //模拟读操作
        public void handleRead(Lock lock) throws InterruptedException{
            try {
                lock.lock();
                System.out.println(Thread.currentThread().getName() + "进入了线程
    ");
                Thread.sleep(1000);
                System.out.println(value);
            } finally {
                lock.unlock();
            }
    
        }
    
        //模拟写操作
        public void handleWrite(Lock lock, int index) throws InterruptedException{
            try {
                lock.lock();
                System.out.println(Thread.currentThread().getName() + "进入了线程");
                Thread.sleep(3000);
                value = index;
                System.out.println("共享资源修改之后: "+value);
            } finally {
                lock.unlock();
            }
        }
    
        public static void main(String[] args) {
            final Lesson18_ReadWriteLock demo = new Lesson18_ReadWriteLock();
    
            //给读线程加上读锁
            Runnable readTarget = new Runnable() {
                @Override
                public void run() {
                    try {
                        demo.handleRead(readLock);
    //                    demo.handleRead(lock);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
    
            //给写线程加上写锁
            Runnable writeTarget = new Runnable() {
                @Override
                public void run() {
                    try {
                        demo.handleWrite(writeLock,new Random().nextInt());
    //                    demo.handleWrite(lock,new Random().nextInt());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
    
            for (int i = 0; i < 8 ; i++) {
                Thread thread = new Thread(readTarget);
                thread.setName("线程" + i);
                thread.start();
            }
    
            for (int i = 8; i < 10; i++) {
                Thread thread = new Thread(writeTarget);
                thread.setName("线程" + i);
                thread.start();
            }
        }
    }

    最后的运行结果:

    线程0进入了线程
    
    线程2进入了线程
    
    线程3进入了线程
    
    线程1进入了线程
    
    线程7进入了线程
    
    线程6进入了线程
    
    线程5进入了线程
    
    1
    1
    1
    1
    1
    1
    1
    线程9进入了线程
    共享资源修改之后: -1565636082
    线程8进入了线程
    共享资源修改之后: 641779894
    线程4进入了线程
    
    641779894
    
    Process finished with exit code 0

    线程8和线程9都是写锁锁住的线程,所以当涉及到他们的时候,线程就会被阻塞

    也就是说会在进入写线程之前会停顿几秒钟,写线程执行完之后再执行写线程或者是读线程也需要停顿几秒钟。

    总结一下就是   读 —— 写,   写 —— 读 , 写 —— 写 之间都会进行阻塞。

    而前面8个线程(0 ~ 7)则是一瞬间完成的,因为读与读之间是可以并行的。

    这里自己的理解,根据代码的执行结果,自己有一些理解,但不一定正确,详细的原理大家还是可以去参考上面给出的那篇文章。

    这里的读写锁的名称是 ReentrantReadWriteLock ,它也是一种可重入的锁,只不过之前的重入锁是互斥的,只允许同一个线程重入,而读写锁也是重入的,但它是允许两个连续的读线程重入。

    关于读写锁就小结到这里了。

    "C:Program FilesJavajdk1.8.0_161injava.exe" "-javaagent:D:program filesIntelliJ IDEA 2018.1.2libidea_rt.jar=45972:D:program filesIntelliJ IDEA 2018.1.2in" -Dfile.encoding=UTF-8 -classpath "C:Program FilesJavajdk1.8.0_161jrelibcharsets.jar;C:Program FilesJavajdk1.8.0_161jrelibdeploy.jar;C:Program FilesJavajdk1.8.0_161jrelibextaccess-bridge-64.jar;C:Program FilesJavajdk1.8.0_161jrelibextcldrdata.jar;C:Program FilesJavajdk1.8.0_161jrelibextdnsns.jar;C:Program FilesJavajdk1.8.0_161jrelibextjaccess.jar;C:Program FilesJavajdk1.8.0_161jrelibextjfxrt.jar;C:Program FilesJavajdk1.8.0_161jrelibextlocaledata.jar;C:Program FilesJavajdk1.8.0_161jrelibext ashorn.jar;C:Program FilesJavajdk1.8.0_161jrelibextsunec.jar;C:Program FilesJavajdk1.8.0_161jrelibextsunjce_provider.jar;C:Program FilesJavajdk1.8.0_161jrelibextsunmscapi.jar;C:Program FilesJavajdk1.8.0_161jrelibextsunpkcs11.jar;C:Program FilesJavajdk1.8.0_161jrelibextzipfs.jar;C:Program FilesJavajdk1.8.0_161jrelibjavaws.jar;C:Program FilesJavajdk1.8.0_161jrelibjce.jar;C:Program FilesJavajdk1.8.0_161jrelibjfr.jar;C:Program FilesJavajdk1.8.0_161jrelibjfxswt.jar;C:Program FilesJavajdk1.8.0_161jrelibjsse.jar;C:Program FilesJavajdk1.8.0_161jrelibmanagement-agent.jar;C:Program FilesJavajdk1.8.0_161jrelibplugin.jar;C:Program FilesJavajdk1.8.0_161jrelib esources.jar;C:Program FilesJavajdk1.8.0_161jrelib t.jar;F:codingfileslearnlearn_javajavaseoutproductionjavase" thread.thread_util.Lesson18_ReadWriteLock线程1进入了线程
    线程0进入了线程
    线程4进入了线程
    线程2进入了线程
    线程3进入了线程
    线程7进入了线程
    线程10进入了线程
    线程8进入了线程
    线程13进入了线程
    线程11进入了线程
    线程6进入了线程
    线程5进入了线程
    线程9进入了线程
    线程15进入了线程
    线程16进入了线程
    线程12进入了线程
    线程14进入了线程
    线程17进入了线程
    111111111111111111线程18进入了线程共享资源修改之后: 22031275线程19进入了线程共享资源修改之后: 709636739
    Process finished with exit code 0

  • 相关阅读:
    ansible-handlers
    LNMP
    编译安装sshpass
    cadence-irun(xrun) 增量编译
    sva 基础语法
    bsub && lsf 介绍
    Perl 输出内容到 excel
    Perl sendmail
    dlopen与dlsym用法
    perl在linux下通过date获取当前时间
  • 原文地址:https://www.cnblogs.com/bax-life/p/9939406.html
Copyright © 2011-2022 走看看