Java 读写锁 之 锁降级
  anLrwkgbyYZS 2023年12月30日 14 0


锁降级 : 是指保持住当前的写锁(已拥有),再获取读锁,随后释放写锁的过程。

1.  锁降级的用途

锁分为读锁 (共享锁)、写锁(排他锁)两种:

  • 一个线程获取了写锁,其他线程无法获取写锁、读锁,进行阻塞;
  • 一个线程获取了读锁,其他线程无法获取写锁(进行阻塞),但是可以获取读锁;

如果只使用写锁,那么释放写锁之后,其他线程就会获取到写锁或读锁,使用锁降级可以在释放写锁前获取读锁,这样其他的线程就只能获取读锁,对这个数据进行读取,但是不能获取写锁进行修改,只有当前线程释放了读锁之后才可以进行修改。

这样有什么好处:

  1. 相对于一直使用写锁,锁降级可以减少其他读线程的阻塞。
public void update() throws Exception {
        // 获取写锁
        reentrantReadWriteLock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread() + "【获取写锁】");

            // 写数据到DB或者共享变量

            // 获取读锁
            reentrantReadWriteLock.readLock().lock();
        } finally {
            // 释放写锁
            reentrantReadWriteLock.writeLock().unlock();
            // 锁降级结束,降级为读锁
        }

        //当前线程消费数据,其他读线程(本博客没有实现)此时也可以消费数据

        //当前线程消费数据完成,释放读锁
        reentrantReadWriteLock.readLock().unlock();
    }

2. 测试样例

完整测试代码:

import java.sql.Time;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 锁降级的学习
 */
public class LockDegradation implements Runnable {

    /**
     * 读写锁
     */
    private ReentrantReadWriteLock reentrantReadWriteLock;

    public LockDegradation() {
        reentrantReadWriteLock = new ReentrantReadWriteLock();
    }

    @Override
    public void run() {
        while (true) {
            try {
                update();
                TimeUnit.SECONDS.sleep(1);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void update() throws Exception {
        reentrantReadWriteLock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread() + "【获取写锁】");

            System.out.println(Thread.currentThread() + "写数据到DB或者共享变量");
            TimeUnit.SECONDS.sleep(1);

            reentrantReadWriteLock.readLock().lock();
            System.out.println(Thread.currentThread() + "【获取读锁】");
        } finally {
            reentrantReadWriteLock.writeLock().unlock();
            System.out.println(Thread.currentThread() + "【释放写锁】锁降级结束,降级为读锁");
            // 锁降级结束,降级为读锁
        }

        System.out.println(Thread.currentThread() + "当前线程消费数据,其他读线程(本博客没有实现)此时也可以消费数据");
        TimeUnit.SECONDS.sleep(1);

        System.out.println(Thread.currentThread() + "当前线程消费数据完成,释放读锁");
        reentrantReadWriteLock.readLock().unlock();
    }

    public static void main(String[] args) {
        LockDegradation lockDegradation = new LockDegradation();
        Thread thread1 = new Thread(lockDegradation);
        Thread thread2 = new Thread(lockDegradation);
        Thread thread3 = new Thread(lockDegradation);
        thread1.start();
        thread2.start();
        thread3.start();
        while (true) {
        }
    }
}

运行结果:

/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/bin/java "-javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=57496:/Applications/IntelliJ IDEA.app/Contents/bin" -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/lib/tools.jar:/Users/shiheng/testworkspace/JavaGrammarLearning/target/classes:/Users/shiheng/software/repository/org/apache/commons/commons-lang3/3.9/commons-lang3-3.9.jar:/Users/shiheng/software/repository/com/vdurmont/emoji-java/5.1.1/emoji-java-5.1.1.jar:/Users/shiheng/software/repository/org/json/json/20170516/json-20170516.jar:/Users/shiheng/software/repository/com/alibaba/fastjson/1.2.62/fastjson-1.2.62.jar:/Users/shiheng/software/repository/org/apache/poi/poi/4.1.1/poi-4.1.1.jar:/Users/shiheng/software/repository/commons-codec/commons-codec/1.13/commons-codec-1.13.jar:/Users/shiheng/software/repository/org/apache/commons/commons-collections4/4.4/commons-collections4-4.4.jar:/Users/shiheng/software/repository/org/apache/commons/commons-math3/3.6.1/commons-math3-3.6.1.jar:/Users/shiheng/software/repository/org/apache/poi/poi-ooxml/4.1.1/poi-ooxml-4.1.1.jar:/Users/shiheng/software/repository/org/apache/commons/commons-compress/1.19/commons-compress-1.19.jar:/Users/shiheng/software/repository/org/apache/xmlbeans/xmlbeans/3.1.0/xmlbeans-3.1.0.jar:/Users/shiheng/software/repository/com/alibaba/easyexcel/1.1.1/easyexcel-1.1.1.jar:/Users/shiheng/software/repository/commons-beanutils/commons-beanutils/1.9.2/commons-beanutils-1.9.2.jar:/Users/shiheng/software/repository/commons-logging/commons-logging/1.1.1/commons-logging-1.1.1.jar:/Users/shiheng/software/repository/commons-collections/commons-collections/3.2.1/commons-collections-3.2.1.jar:/Users/shiheng/software/repository/cglib/cglib/2.2/cglib-2.2.jar:/Users/shiheng/software/repository/asm/asm/3.1/asm-3.1.jar:/Users/shiheng/software/repository/io/reactivex/rxjava2/rxjava/2.2.21/rxjava-2.2.21.jar:/Users/shiheng/software/repository/org/reactivestreams/reactive-streams/1.0.3/reactive-streams-1.0.3.jar LockDegradation
Thread[Thread-0,5,main]【获取写锁】
Thread[Thread-0,5,main]写数据到DB或者共享变量
Thread[Thread-0,5,main]【获取读锁】
Thread[Thread-0,5,main]【释放写锁】锁降级结束,降级为读锁
Thread[Thread-0,5,main]当前线程消费数据,其他读线程(本博客没有实现)此时也可以消费数据
Thread[Thread-0,5,main]当前线程消费数据完成,释放读锁
Thread[Thread-1,5,main]【获取写锁】
Thread[Thread-1,5,main]写数据到DB或者共享变量
Thread[Thread-1,5,main]【获取读锁】
Thread[Thread-1,5,main]【释放写锁】锁降级结束,降级为读锁
Thread[Thread-1,5,main]当前线程消费数据,其他读线程(本博客没有实现)此时也可以消费数据
Thread[Thread-1,5,main]当前线程消费数据完成,释放读锁
Thread[Thread-2,5,main]【获取写锁】
Thread[Thread-2,5,main]写数据到DB或者共享变量
Thread[Thread-2,5,main]【获取读锁】
Thread[Thread-2,5,main]【释放写锁】锁降级结束,降级为读锁
Thread[Thread-2,5,main]当前线程消费数据,其他读线程(本博客没有实现)此时也可以消费数据
Thread[Thread-2,5,main]当前线程消费数据完成,释放读锁
Thread[Thread-0,5,main]【获取写锁】
Thread[Thread-0,5,main]写数据到DB或者共享变量
Thread[Thread-0,5,main]【获取读锁】
Thread[Thread-0,5,main]【释放写锁】锁降级结束,降级为读锁
Thread[Thread-0,5,main]当前线程消费数据,其他读线程(本博客没有实现)此时也可以消费数据
Thread[Thread-0,5,main]当前线程消费数据完成,释放读锁
Thread[Thread-1,5,main]【获取写锁】
Thread[Thread-1,5,main]写数据到DB或者共享变量
Thread[Thread-1,5,main]【获取读锁】
Thread[Thread-1,5,main]【释放写锁】锁降级结束,降级为读锁
Thread[Thread-1,5,main]当前线程消费数据,其他读线程(本博客没有实现)此时也可以消费数据
Thread[Thread-1,5,main]当前线程消费数据完成,释放读锁
Thread[Thread-2,5,main]【获取写锁】
Thread[Thread-2,5,main]写数据到DB或者共享变量
Thread[Thread-2,5,main]【获取读锁】
Thread[Thread-2,5,main]【释放写锁】锁降级结束,降级为读锁
Thread[Thread-2,5,main]当前线程消费数据,其他读线程(本博客没有实现)此时也可以消费数据
Thread[Thread-2,5,main]当前线程消费数据完成,释放读锁
...

参考文献:

  • Java并发编程的艺术 / 方腾飞,魏鹏,魏晓明著 .  ——北京:机械工业出版社,2015.7
【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年12月30日 0

暂无评论

推荐阅读
anLrwkgbyYZS