zoukankan      html  css  js  c++  java
  • 可重入锁 & 不可重入锁

    可重入锁指同一个线程可以再次获得之前已经获得的锁,避免产生死锁。

    Java中的可重入锁:synchronized 和 java.util.concurrent.locks.ReentrantLock。
    1、synchronized 使用方便,编译器来加锁,是非公平锁。
    2、ReenTrantLock 使用灵活,锁的公平性可以定制。
    3、相同加锁场景下,推荐使用 synchronized。

    ReenTrantLock可以指定是公平锁还是非公平锁。而synchronized只能是非公平锁。所谓的公平锁就是先等待的线程先获得锁。

    锁的实现:
    Synchronized是依赖于JVM实现的,而ReenTrantLock是JDK实现的,有什么区别,说白了就类似于操作系统来控制实现和用户自己敲代码实现的区别。前者的实现是比较难见到的,后者有直接的源码可供阅读。

    ReenTrantLock实现的原理:
    简单来说,ReenTrantLock的实现是一种自旋锁,通过循环调用CAS操作来实现加锁。它的性能比较好也是因为避免了使线程进入内核态的阻塞状态。想尽办法避免线程进入内核的阻塞状态是我们去分析和理解锁设计的关键钥匙。

    模拟ReenTrantLock用法:假设有两个线程(A线程、B线程)去调用print(String name)方法,A线程负责打印'zhangsan'字符串,B线程负责打印'lisi'字符串。
    a、当没有为print(String name)方法加上锁时,则会产生A线程还没有执行完毕,B线程已开始执行,那么打印出来的name就会出现如下问题。

    b、当为print(String name)方法加上锁时,则会产生A执行完毕后,B线程才执行print(String name)方法,达到互斥或者说同步效果。

    package com.lynch.lock;
    
    /**
     *    ReentrantLock用法
     *
     * @author Lynch
     */
    public class ReentrantLockTest {
    
        public static void main(String[] args) {
            final Outputer outputer = new Outputer();
    
            //线程A打印zhangsan
            new Thread(() -> {
                while (true) {
                    sleep();
                    outputer.output("zhangsan");
                }
            }).start();
            
            //线程B打印lisi
            new Thread(() -> {
                while (true) {
                    sleep();
                    outputer.output("lisi");
                }
            }).start();
    
        }
    
        private static void sleep() {
            try {
                Thread.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    package com.lynch.lock;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     * 打印字符
     *
     * @author Lynch
     */
    public class Outputer {
        Lock lock = new ReentrantLock();
    
        public void output(String name) {
            try {
                lock.lock();
                
                int len = name.length();
                for (int i = 0; i < len; i++) {
                    System.out.print(name.charAt(i));
                }
                System.out.println();
            } finally {
                lock.unlock();
            }
        }
    }

     

  • 相关阅读:
    WPF 关于拖拽打开文件的注意事项
    asp.net core 3.1中对Mongodb BsonDocument的序列化和反序列化支持
    用百度webuploader分片上传大文件
    多线程学习笔记
    web.config数据库连接字符串加密
    Visual Studio 2010 常用快捷方式
    Team Foundation Server 2013 日常使用使用手册(四)分支与合并
    Team Foundation Server 2013 日常使用使用手册(三)上传新工程、创建任务、创建bug、设置预警
    Team Foundation Server 2013 日常使用使用手册(二)修改、签入、撤销、回滚、对比代码变更
    Team Foundation Server 2013 日常使用使用手册(一)-本地连接TFS、查看任务
  • 原文地址:https://www.cnblogs.com/linjiqin/p/9698610.html
Copyright © 2011-2022 走看看