美文网首页并发编程程序员
Java并发编程——锁与可重入锁

Java并发编程——锁与可重入锁

作者: anytimekaka | 来源:发表于2016-03-14 23:19 被阅读12145次

上一篇文章中讲述了信号量和互斥量,其中互斥量一般用于保证对于资源的互斥访问,和锁的本质一样。本文讲述简单锁的实现和可重入锁的基本原理。

简单锁

在讲述简单锁的实现之前,我们先来看一个锁的应用例子:

public class Counter{
    private Lock lock = new Lock();
    private int count = 0;
    public int inc(){
        lock.lock();
        this.count++;
        lock.unlock();
        return count;
    }
}

上面的程序中,由于this.count++这一操作分多步执行,在多线程环境中可能出现结果不符合预期的情况,这段代码称之为 临界区 ,所以需要使用lock来保证其原子性。

Lock的实现:

public class Lock{
    private boolean isLocked = false;
    public synchronized void lock() throws InterruptedException{
        while(isLocked){    //不用if,而用while,是为了防止假唤醒
            wait();
        }
        isLocked = true;
    }
    public synchronized void unlock(){
        isLocked = false;
        notify();
    }
}

说明:当isLocked为true时,调用lock()的线程在wait()阻塞。 为防止该线程虚假唤醒,程序会重新去检查isLocked条件。 如果isLocked为false,当前线程会退出while(isLocked)循环,并将isLocked设回true,让其它正在调用lock()方法的线程能够在Lock实例上加锁。当线程完成了临界区中的代码,就会调用unlock()。执行unlock()会重新将isLocked设置为false,并且唤醒 其中一个 处于等待状态的线程。

锁的可重入性

同样,先举例来说明锁的可重入性:

public class UnReentrant{
    Lock lock = new Lock();
    public void outer(){
        lock.lock();
        inner();
        lock.unlock();
    }
    public void inner(){
        lock.lock();
        //do something
        lock.unlock();
    }
}

outer中调用了inner,outer先锁住了lock,这样inner就不能再获取lock。其实调用outer的线程已经获取了lock锁,但是不能在inner中重复利用已经获取的锁资源,这种锁即称之为 不可重入 。通常也称为 自旋锁 。相对来说,可重入就意味着:线程可以进入任何一个它已经拥有的锁所同步着的代码块。

可重入锁的基本原理

我们在上面的Lock基础上作一些修改:

public class Lock{
    boolean isLocked = false;
    Thread  lockedBy = null;
    int lockedCount = 0;
    public synchronized void lock()
        throws InterruptedException{
        Thread callingThread = Thread.currentThread();
        while(isLocked && lockedBy != callingThread){
            wait();
        }
        isLocked = true;
        lockedCount++;
        lockedBy = callingThread;
  }
    public synchronized void unlock(){
        if(Thread.curentThread() == this.lockedBy){
            lockedCount--;
            if(lockedCount == 0){
                isLocked = false;
                notify();
            }
        }
    }
}
  • lockBy:保存已经获得锁实例的线程,在lock()判断调用lock的线程是否已经获得当前锁实例,如果已经获得锁,则直接跳过while,无需等待。
  • lockCount:记录同一个线程重复对一个锁对象加锁的次数。否则,一次unlock就会解除所有锁,即使这个锁实例已经加锁多次了。

Java中常用的锁的属性

synchronized:可重入锁;
java.util.concurrent.locks.ReentrantLock:可重入锁;

相关文章

  • 2020-02-01 2.2.1 可重入锁与不可重入锁。

    本文是Java线程安全和并发编程知识总结的一部分。 2.2.1 可重入锁与不可重入锁。 JDK中提供的锁,基本都是...

  • java并发-独占锁与共享锁,公平锁与非公平锁,重入锁与非重入锁

    java并发-乐观锁与悲观锁,独占锁与共享锁,公平锁与非公平锁,重入锁与非重入锁 java 中的锁 -- 偏向锁、...

  • Java并发编程——锁与可重入锁

    上一篇文章中讲述了信号量和互斥量,其中互斥量一般用于保证对于资源的互斥访问,和锁的本质一样。本文讲述简单锁的实现和...

  • Java并发开篇--ReentrantLock公平锁的可重入性

    Java并发编程--ReentrantLock可重入性探索 我们直接先看其公平锁情况下的可重入性到底是怎么回事,由...

  • java并发编程--可重入锁

    java的并发锁机制可以通过synchronized实现,可重入性概念简单来说就是:就是在一个synchroniz...

  • 谈谈对锁的理解

    参考:通俗易懂 悲观锁、乐观锁、可重入锁、自旋锁、偏向锁、轻量/重量级锁、读写锁、各种锁及其Java实现! 在并发...

  • JDK并发包

    java高并发程序设计 - 网易云课堂 一、重入锁 重入锁是synchronized,Object.wait(),...

  • Java并发编程-重入锁

    章节目录 什么是重入锁 底层实现-如何实现重入 公平与非公平获取锁的区别与底层实现 1.什么是重入锁 1.1 重入...

  • java可重入锁

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

  • java并发

    1.并发编程中的锁 并发编程中的各种锁java高并发锁的3种实现Java并发机制及锁的实现原理 2.线程池核心线程...

网友评论

  • 张利强:这种锁即称之为 不可重入 。通常也称为 自旋锁 。
    -------这句话是谬误,自旋锁应该说的是锁优化的技术。
  • 98e147d162d3:自旋锁的定义不对吧。
    张利强:这种锁即称之为 不可重入 。通常也称为 自旋锁 。
    -------这句话是谬误,自旋锁应该说的是锁优化的技术。
  • 574d1aec84b0:Lock类的lock()不要加synchroinized。
  • passerbywhu:lock那里加了synchronized都已经获得锁了。。。还要去做isLocked判断干嘛。。。而且synchronized方法结束后就自动释放锁了。。。
    574d1aec84b0::smile: 加了就阻塞了,还怎么可重入哦。
  • jiang2022:简洁明了,点个赞!
  • 莲塘之水:写的很精彩,从源码的角度分析,目前为止看到最清晰的解释!!!
  • chenhong_f1e2:赞
    03f718315140:@雷诺_c615 你们怕是石乐志
    屎倒淋头还嚼便:@dev4mobiles 还真是,感觉不用加
    dev4mobiles:lock 实现你加上synchroinized 干嘛?

本文标题:Java并发编程——锁与可重入锁

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