美文网首页
锁 - 可重入 vs 不可重入

锁 - 可重入 vs 不可重入

作者: 面向对象架构 | 来源:发表于2022-11-21 00:13 被阅读0次

可重入锁

在多线程编程和信号处理过程中,经常会遇到可重入(reentrance)线程安全(thread-safe)

什么是重入

函数在执行时,由于外部原因或内部调用,又一次进入该函数执行。

重入一般发生在:

  1. 多个线程同时执行该函数
  2. 函数自身调用自身

什么是可重入函数

可重入的英文关键词是 reentrant 或 re-entrant

解释:运行某个函数或者代码时由于某个原因(中断或者抢占资源问题)而中止函数或代码的运行,等到问题解决后,重新进入该函数或者代码继续运行,其结果不受影响。那么这个函数或者代码就称为可重入的。简而言之,在异步环境下,可以重新进入。

只要函数中的数据能被多个进程或者线程共享,那么这个函数就一定不是可重入函数。

不可重入会带来不能预见的结果,尤其在内核中,如果操作不当会让系统直接挂掉。所以内核代码一定要是可重入的。

可重入的函数的特点(不能有可被其他函数或代码所共享的数据):

  1. 不使用任何静态或全局的非常量对象
  2. 不返回任何静态或全局的非常量对象的指针或地址
  3. 只依赖于或只能处理调用方提供的参数/数据
  4. 不依赖任何单个资源的锁
  5. 不调用任何不可重入的函数

可重入与线程安全的关系

一般而言,可重入的函数一定是线程安全的,反之则不一定成立。在不加锁的前提下,如果一个函数用到了全局或静态变量,那么它不是线程安全的,也不是可重入的。如果我们加以改进,对全局变量的访问加锁,此时它是线程安全的但不是可重入的,因为通常的枷锁方式是针对不同线程的访问(如Java的Synchronized),当同一个线程多次访问就会出现问题。


01-technology_B-advanced_B02-Function-Diff-In-ThreadSafe-And-Reentrant.png

与线程安全不同,可重入强调对单个线程执行时重新进入同一个子程序仍然是安全的。

两者的区别:

(1)线程安全不一定是可重入的,而可重入函数一定是线程安全的。

(2)线程安全是多个线程下引起的,但可重入函数可以在只有一个线程的情况下发生。

(3)若一个函数中存在全局变量,那么这个函数既不是线程安全的也不是可重入的。

(4)线程安全函数能够使不同的线程访问同一块地址空间,而可重入函数要求不同的执行流对数据的操作互不影响结果是相同的。

可重入锁

典型的可重入锁:ReentrantLock、synchronized、Lock、ReentrantReadWriteLock.ReadLock、ReentrantReadWriteLock.WriteLock

可重入锁,也叫递归锁,指的是线程可以进入任何一个它已经拥有锁的所有同步代码块。

可重复可递归调用的锁,在外层使用锁之后,在内层仍然可以使用,并且不会发生死锁(前提是同一个对象或者class)。

public class Test implements Runnable {
     
        public synchronized void get(){
            System.out.println(Thread.currentThread().getId());
            set();
        }
     
        public synchronized void set(){
            System.out.println(Thread.currentThread().getId());
        }
     
        @Override
        public void run() {
            get();
        }
        public static void main(String[] args) {
            Test ss=new Test();
            new Thread(ss).start();
            new Thread(ss).start();
            new Thread(ss).start();
        }
    }
     
    public class Test implements Runnable {
        ReentrantLock lock = new ReentrantLock();
     
        public void get() {
            lock.lock();
            System.out.println(Thread.currentThread().getId());
            set();
            lock.unlock();
        }
     
        public void set() {
            lock.lock();
            System.out.println(Thread.currentThread().getId());
            lock.unlock();
        }
     
        @Override
        public void run() {
            get();
        }
     
        public static void main(String[] args) {
            Test ss = new Test();
            new Thread(ss).start();
            new Thread(ss).start();
            new Thread(ss).start();
        }
    }

同一个线程id被连续输出两次。
结果如下:
Threadid: 8
Threadid: 8
Threadid: 10
Threadid: 10
Threadid: 9
Threadid: 9

不可重入锁

不可重入锁是指:与重入锁相反,不可递归调用,递归调用就发生死锁

// 自旋实现的不可重入锁
public class Lock {
     private boolean isLocked = false;
     public synchronized void lock() throws InterruptedException{
         while(isLocked){    
             wait();
         }
         isLocked = true;
     }
     public synchronized void unlock(){
         isLocked = false;
         notify();
     }
}

import java.util.concurrent.atomic.AtomicReference;

public class UnreentrantLock {
    private AtomicReference owner = new AtomicReference();
    public void lock() {
        Thread current = Thread.currentThread();
        //这句是很经典的“自旋”语法,AtomicInteger中也有
        for(;;) {
            if(!owner.compareAndSet(null, current)) {
                return;
            }
        }
    }

    public void unlock(){
        Thread current = Thread.currentThread();
        owner.compareAndSet(current,null);
    }
}

相关文章

  • 锁 - 可重入 vs 不可重入

    可重入锁 在多线程编程和信号处理过程中,经常会遇到可重入(reentrance)和线程安全(thread-safe...

  • 可重入锁vs不可重入锁

    一、代码展示 先设计一个不可重入锁: 运行结果: 可以看到同一个线程,重复获取锁失败,形成死锁,这就是不可重入锁。...

  • 可重入锁 VS 非可重入锁

    可重入锁又名递归锁,是指在同一个线程在外层方法获取锁的时候,再进入该线程的内层方法会自动获取锁(前提锁对象得是同一...

  • 各种锁的概念

    锁的概念 可重入不可重入公平锁非公平锁锁中断通过一个故事理解可重入锁的机制 - 小勇DW3 - 博客园[https...

  • ReentrantLock 源码分析

    锁的基本概念 可重入锁 Reentrant 就是可重入的意思,如果锁具备可重入性,则称作为可重入锁。像synchr...

  • 不可重入锁和可重入锁

    这个方法在下面的一个场景里面执行不会有问题,都可以很好的处理两个业务对同一个号码互斥执行的需求,如果两个方法并发执...

  • 可重入锁和不可重入锁

    不可重入锁 先来设计一种锁 这其实是个不可重入锁,举个例子 当调用print()方法时,获得了锁,这时就无法再调用...

  • 不可重入锁和可重入锁

    所谓不可重入锁,即若当前线程执行某个方法已经获取了该锁,那么在方法中尝试再次获取锁时,就会获取不到被阻塞; 所谓可...

  • java可重入锁

    可重入概念: java的可重入锁: 可重入锁的一种实现方式: 可重入锁的两种使用例子: 例子1: 例子2: 例子1...

  • Java 可重入锁 公平锁 读写锁

    1.可重入锁 如果锁具备可重入性,则称作为可重入锁。 像synchronized和ReentrantLock都是可...

网友评论

      本文标题:锁 - 可重入 vs 不可重入

      本文链接:https://www.haomeiwen.com/subject/jdasxdtx.html