精华内容
下载资源
问答
  • 今天小编就为大家分享一篇关于Java可重入锁的实现原理与应用场景,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
  • Java中的可重入锁和不可重入锁

    千次阅读 2019-12-02 10:20:27
    的简单应用 用lock来保证原子性(this.count++这段代码称为临界区) 什么是原子性,就是不分,从头执行到尾,不能被其他线程同时执行。 通过CAS来实现原子操作 CAS(Compare and Swap): CAS操作需要输入...

    锁的简单应用


    用lock来保证原子性(this.count++这段代码称为临界区)

    什么是原子性,就是不可分,从头执行到尾,不能被其他线程同时执行。

    可通过CAS来实现原子操作

    CAS(Compare and Swap):

    CAS操作需要输入两个数值,一个旧值(期望操作前的值)和一个新值,在操作期间先比较下旧值有没有发生变化,如果没有发生变化,才交换成新值,发生了变化则不交换。

    CAS主要通过compareAndSwapXXX()方法来实现,而这个方法的实现需要涉及底层的unsafe类

    unsafe类: java不能直接访问操作系统底层,而是通过本地方法来访问。Unsafe类提供了硬件级别的原子操作

    这里有个介绍原子操作的博客

    https://my.oschina.net/xinxingegeya/blog/499223

    还有对unsafe类详解的博客

    http://www.cnblogs.com/mickole/articles/3757278.html

     1 public class Counter{
     2     private Lock lock = new Lock();
     3     private int count = 0;
     4     public int inc(){
     5         lock.lock();
     6         this.count++;
     7         lock.unlock();
     8         return count;
     9     }
    10 }
    

    不可重入锁


    设计如下:

     1 public class Lock{
     2     private boolean isLocked = false;
     3     public synchronized void lock() throws InterruptedException{
     4         while(isLocked){    
     5             wait();
     6         }
     7         isLocked = true;
     8     }
     9     public synchronized void unlock(){
    10         isLocked = false;
    11         notify();
    12     }
    13 }
    

    这其实是个不可重入锁,举个例子

     1 public class Count{
     2     Lock lock = new Lock();
     3     public void print(){
     4         lock.lock();
     5         doAdd();
     6         lock.unlock();
     7     }
     8     public void doAdd(){
     9         lock.lock();
    10         //do something
    11         lock.unlock();
    12     }
    13 }
    

    当调用print()方法时,获得了锁,这时就无法再调用doAdd()方法,这时必须先释放锁才能调用,所以称这种锁为不可重入锁,也叫自旋锁。

    可重入锁


    设计如下:

     1 public class Lock{
     2     boolean isLocked = false;
     3     Thread  lockedBy = null;
     4     int lockedCount = 0;
     5     public synchronized void lock()
     6             throws InterruptedException{
     7         Thread thread = Thread.currentThread();
     8         while(isLocked && lockedBy != thread){
     9             wait();
    10         }
    11         isLocked = true;
    12         lockedCount++;
    13         lockedBy = thread;
    14     }
    15     public synchronized void unlock(){
    16         if(Thread.currentThread() == this.lockedBy){
    17             lockedCount--;
    18             if(lockedCount == 0){
    19                 isLocked = false;
    20                 notify();
    21             }
    22         }
    23     }
    24 }
    

    相对来说,可重入就意味着: 一个线程可以进入任何一个 该线程 已经拥有的锁所同步着的代码块

    第一个线程执行print()方法,得到了锁,使lockedBy等于当前线程,也就是说,执行的这个方法的线程获得了这个锁,执行add()方法时,同样要先获得锁(即调用lock.lock()),因不满足while循环的条件(isLocked(=true,因为该线程调用print()方法时就获得该锁了);但是这里与不可重入锁的区别是有个lockedBy(即表示现在哪个线程持有锁);因为调用add()方法的是和调用print()的是同一个线程),也就是不等待,继续进行,将此时的lockedCount变量,也就是当前获得锁的数量加一,当释放了所有的锁(即得调用获得锁数量次数的unlock),才执行notify()。

    如果在执行这个方法时,有第二个线程想要执行这个方法,因为lockedBy不等于第二个线程,导致这个线程进入了循环,也就是等待(阻塞),不断执行wait()方法。只有当第一个线程释放了所有的锁(即第一个线程调用了多少次lock()方法就得调用多少次unlock()方法释放锁),执行了notify()方法,第二个线程才得以跳出循环,继续执行。

    这就是可重入锁的特点。

    可重入锁与不可重入锁对比, 简单来说就是:可重入锁会多两个属性(1、获得该锁的线程;2、获得该锁的次数),根据第一个属性判断,如果是持有该锁的那个线程又来lock,不会被阻塞(wait),而是在上锁的次数加一(表示这个线程又锁了一次(重入)),只有该线程unlock的次数达到上锁的次数(即第二个属性等于0),才会唤醒其他线程。

    java中常用的可重入锁

    synchronized

    java.util.concurrent.locks.ReentrantLock


    其他

    首先我们这里提到的锁,是把所需要的代码块,资源,或数据锁上,在操作他们的时候只允许一个线程去做操作。最终结果是为了保证cpu计算结果的正确性。

    对不可重入锁的理解:

    public class Test{
         Lock lock = new Lock();
         public void methodA(){
             lock.lock();
             ...........;
             methodB();
             ...........;
             lock.unlock();
         }
         public void methodB(){
             lock.lock();
             ...........;
             lock.unlock();
         }
    }
    

    A方法获取lock锁去锁住一段需要做原子性操作的B方法时,如果这段B方法又需要去做原子性操作,那么A方法就必定要与B方法出现死锁。这种会出现问题的重入一把锁的情况,叫不可重入锁。

    A方法需要等B方法执行完才能解锁,但是B方法想执行完代码又必须要lock锁来加锁。A的锁未解锁前,其他代码块无法使用此锁来加锁。这是由这个不可重入锁决定的。

    那么平时我们又有需要重入一把锁的需求!!!!比如A方法是个原子性操作,但它有需要调用B方法的原子性操作,他们还争抢的是同一个临界资源,因此需要同一把锁来加锁(ps:争抢同一临界资源的实质就是对同一把锁的争抢)

    参考文章:
    https://www.cnblogs.com/xdyixia/p/9383388.html
    https://blog.csdn.net/qq_29519041/article/details/86583945
    https://www.cnblogs.com/dj3839/p/6580765.html

    展开全文
  • Java锁之可重入锁介绍

    2020-09-04 01:21:41
    主要介绍了Java锁之可重入锁介绍,可重入锁,也叫做递归锁,指的是同一线程外层函数获得锁之后,内层递归函数仍然获取该锁的代码,但不受影响,需要的朋友可以参考下
  • 主要介绍了简单了解Java中的可重入锁,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • Java可重入锁和可重入锁理解

    万次阅读 多人点赞 2018-06-28 15:30:35
    最近正在阅读Java ReentrantLock源码,始终对可重入和不可重入概念理解不透彻,进行学习后记录在这里。 基础知识 Java多线程的wait()方法和notify()方法 这两个方法是成对出现和使用的,要执行这两个方法,一个...

    最近正在阅读Java ReentrantLock源码,始终对可重入和不可重入概念理解不透彻,进行学习后记录在这里。

    基础知识

    Java多线程的wait()方法和notify()方法

    这两个方法是成对出现和使用的,要执行这两个方法,有一个前提就是,当前线程必须获其对象的monitor(俗称“锁”),否则会抛出IllegalMonitorStateException异常,所以这两个方法必须在同步块代码里面调用。

    wait():阻塞当前线程

    notify():唤起被wait()阻塞的线程

    不可重入锁

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

    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();
        }
    }

    使用该锁:

    public class Count{
        Lock lock = new Lock();
        public void print(){
            lock.lock();
            doAdd();
            lock.unlock();
        }
        public void doAdd(){
            lock.lock();
            //do something
            lock.unlock();
        }
    }

    当前线程执行print()方法首先获取lock,接下来执行doAdd()方法就无法执行doAdd()中的逻辑,必须先释放锁。这个例子很好的说明了不可重入锁。

    可重入锁

    接下来,我们设计一种可重入锁

    public class Lock{
        boolean isLocked = false;
        Thread  lockedBy = null;
        int lockedCount = 0;
        public synchronized void lock()
                throws InterruptedException{
            Thread thread = Thread.currentThread();
            while(isLocked && lockedBy != thread){
                wait();
            }
            isLocked = true;
            lockedCount++;
            lockedBy = thread;
        }
        public synchronized void unlock(){
            if(Thread.currentThread() == this.lockedBy){
                lockedCount--;
                if(lockedCount == 0){
                    isLocked = false;
                    notify();
                }
            }
        }
    }

    所谓可重入,意味着线程可以进入它已经拥有的锁的同步代码块儿。

    我们设计两个线程调用print()方法,第一个线程调用print()方法获取锁,进入lock()方法,由于初始lockedBy是null,所以不会进入while而挂起当前线程,而是是增量lockedCount并记录lockBy为第一个线程。接着第一个线程进入doAdd()方法,由于同一进程,所以不会进入while而挂起,接着增量lockedCount,当第二个线程尝试lock,由于isLocked=true,所以他不会获取该锁,直到第一个线程调用两次unlock()将lockCount递减为0,才将标记为isLocked设置为false。

    可重入锁的概念和设计思想大体如此,Java中的可重入锁ReentrantLock设计思路也是这样

    展开全文
  • 今天小编就为大家分享一篇关于Java源码解析之可重入锁ReentrantLock,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
  • java可重入锁与不可重入锁

    万次阅读 多人点赞 2018-08-28 11:08:58
    synchronized 和 ReentrantLock 都是可重入锁可重入锁的意义在于防止死锁。 实现原理是通过为每个锁关联一个请求计数器和一个占有它的线程。当计数为0时,认为锁是未被占有的;线程请求一个未被占有的锁时,...

    所谓重入锁,指的是以线程为单位,当一个线程获取对象锁之后,这个线程可以再次获取本对象上的锁,而其他的线程是不可以的。

    synchronized 和   ReentrantLock 都是可重入锁。

    可重入锁的意义在于防止死锁。

    实现原理是通过为每个锁关联一个请求计数器和一个占有它的线程。当计数为0时,认为锁是未被占有的;线程请求一个未被占有的锁时,JVM将记录锁的占有者,并且将请求计数器置为1 。

    如果同一个线程再次请求这个锁,计数将递增;

    每次占用线程退出同步块,计数器值将递减。直到计数器为0,锁被释放。

    关于父类和子类的锁的重入:子类覆写了父类的synchonized方法,然后调用父类中的方法,此时如果没有重入的锁,那么这段代码将产生死锁(很好理解吧)。

    例子:

    比如说A类中有个方法public synchronized methodA1(){

            methodA2();

    }

    而且public synchronized methodA2(){

                        //具体操作

    }

    也是A类中的同步方法,当当前线程调用A类的对象methodA1同步方法,如果其他线程没有获取A类的对象锁,那么当前线程就获得当前A类对象的锁,然后执行methodA1同步方法,方法体中调用methodA2同步方法,当前线程能够再次获取A类对象的锁,而其他线程是不可以的,这就是可重入锁。

     

    代码演示:

    不可重入锁:

    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();
        }
    }

    使用该锁:

    public class Count{
        Lock lock = new Lock();
        public void print(){
            lock.lock();
            doAdd();
            lock.unlock();
        }
        public void doAdd(){
            lock.lock();
            //do something
            lock.unlock();
        }
    }

    当前线程执行print()方法首先获取lock,接下来执行doAdd()方法就无法执行doAdd()中的逻辑,必须先释放锁。这个例子很好的说明了不可重入锁。

    可重入锁:

    接下来,我们设计一种可重入锁

    public class Lock{
        boolean isLocked = false;
        Thread  lockedBy = null;
        int lockedCount = 0;
        public synchronized void lock()
                throws InterruptedException{
            Thread thread = Thread.currentThread();
            while(isLocked && lockedBy != thread){
                wait();
            }
            isLocked = true;
            lockedCount++;
            lockedBy = thread;
        }
        public synchronized void unlock(){
            if(Thread.currentThread() == this.lockedBy){
                lockedCount--;
                if(lockedCount == 0){
                    isLocked = false;
                    notify();
                }
            }
        }
    }

    所谓可重入,意味着线程可以进入它已经拥有的锁的同步代码块儿。

    我们设计两个线程调用print()方法,第一个线程调用print()方法获取锁,进入lock()方法,由于初始lockedBy是null,所以不会进入while而挂起当前线程,而是是增量lockedCount并记录lockBy为第一个线程。接着第一个线程进入doAdd()方法,由于同一进程,所以不会进入while而挂起,接着增量lockedCount,当第二个线程尝试lock,由于isLocked=true,所以他不会获取该锁,直到第一个线程调用两次unlock()将lockCount递减为0,才将标记为isLocked设置为false。

    可重入锁的概念和设计思想大体如此,Java中的可重入锁ReentrantLock设计思路也是这样。

     

    synchronized和ReentrantLock 都是可重入锁。ReentrantLock与synchronized比较:

    1.前者使用灵活,但是必须手动开启和释放锁

    2.前者扩展性好,有时间锁等候(tryLock( )),可中断锁等候(lockInterruptibly( )),锁投票等,适合用于高度竞争锁和多个条件变量的地方

    3.前者提供了可轮询的锁请求,可以尝试去获取锁(tryLock( )),如果失败,则会释放已经获得的锁。有完善的错误恢复机制,可以避免死锁的发生。

    摘自:JAVA可重入锁与不可重入锁   和   Java不可重入锁和可重入锁理解

     

    展开全文
  • Java中的可重入锁

    千次阅读 2019-05-28 13:01:29
    原文地址:http://ifeve.com/java_lock_see4/ 转载...可重入锁,也叫做递归锁,指的是同一线程 外层函数获得锁之后 ,内层递归函数仍然获取该锁的代码,但不受影响。 在JAVA环境下 ReentrantLock 和synchronized...

    原文地址:http://ifeve.com/java_lock_see4/   转载自 : 并发编程网 – ifeve.com


    本文里面讲的是广义上的可重入锁,而不是单指JAVA下的ReentrantLock。

    可重入锁,也叫做递归锁,指的是同一线程 外层函数获得锁之后 ,内层递归函数仍然有获取该锁的代码,但不受影响。

    在JAVA环境下 ReentrantLock 和synchronized 都是 可重入锁。

    下面是使用实例:

    package reentrantLock;
    
    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();
        }
    }
    

    运行截图:

    package reentrantLock;
    
    import java.util.concurrent.locks.ReentrantLock;
    
    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();
        }
    }

    可重入锁最大的作用是避免死锁

    我们以自旋锁作为例子,

    public class SpinLock {
    	private AtomicReference<Thread> owner =new AtomicReference<>();
    	public void lock(){
    		Thread current = Thread.currentThread();
    		while(!owner.compareAndSet(null, current)){
    		}
    	}
    	public void unlock (){
    		Thread current = Thread.currentThread();
    		owner.compareAndSet(current, null);
    	}
    }

    对于自旋锁来说,

    1、若有同一线程两调用lock() ,会导致第二次调用lock位置进行自旋,产生了死锁说明这个锁并不是可重入的。(在lock函数内,应验证线程是否为已经获得锁的线程)

    2、若1问题已经解决,当unlock()第一次调用时,就已经将锁释放了。实际上不应释放锁。(采用计数次进行统计)修改之后,如下:

    public class SpinLock1 {
    	private AtomicReference<Thread> owner =new AtomicReference<>();
    	private int count =0;
    	public void lock(){
    		Thread current = Thread.currentThread();
    		if(current==owner.get()) {
    			count++;
    			return ;
    		}
    
    		while(!owner.compareAndSet(null, current)){
    
    		}
    	}
    	public void unlock (){
    		Thread current = Thread.currentThread();
    		if(current==owner.get()){
    			if(count!=0){
    				count--;
    			}else{
    				owner.compareAndSet(current, null);
    			}
    
    		}
    
    	}
    }

    该自旋锁即为可重入锁。

    展开全文
  • java可重入锁的意义

    2019-12-12 11:16:36
    java默认的机制都是非公平的,非公平的意思就是线程一,线程二同时取循环执行一串被住的代码块,执行的先后顺序是不确定的,也就是说不一行是先来后到的,这就是非公平。执行结果是下面这样,这就是默认的线程...
  • Java并发编程:用AQS写一把可重入锁

    千次阅读 多人点赞 2018-11-12 02:32:37
    Java并发编程:自己动手写一把可重入锁 详述了如何用synchronized同步的方式来实现一把可重入锁,今天我们来效仿ReentrantLock类用AQS来改写一下这把锁。要想使用AQS为我们服务,首先得弄懂三个问题:AQS是什么?AQS...
  • java 手动实现一个可重入锁

    千次阅读 2018-04-17 16:13:34
    手动实现一个可重入锁下面代码给出了一个手动实现的可重入锁,MyLock类,实现了Lock接口,需要编写的两个函数为lock()和unlock()。isLocked变量用来判断当前是否线程使用,若没有,则为false。lockBy变量保存了...
  • 轻松学习java可重入锁(ReentrantLock)的实现原理

    万次阅读 多人点赞 2016-08-28 14:17:46
    前言相信学过java的人都知道 synchronized 这个关键词,也知道它用于控制多线程对并发...如果真是这样,而且你兴趣了解,今天我将带领你轻松的学习下java中非常重要,也非常基础的可重入锁-ReentrantLock的实现机制。
  • Java多线程的wait()方法和notify()方法: wait():阻塞当前线程 notify():唤起被wait()阻塞的线程 这两个方法是成对出现和使用的,要执行这两个方法,一个前提就是,当前线程必须获其...不可重入锁: public...
  • 什么是可重入锁以及在Java中的应用

    千次阅读 2018-04-23 00:14:55
    可重入锁,顾名思义是指可以重复获取锁。对于一个线程,在外部获取锁后进行内部方法执行时同样可以再次获取到锁,不用阻塞等待锁的释放。可重入锁的意义一定程度上避免了死锁。 在Java中,可以使用关键字...
  • 可重入锁究竟是什么意思,以前是囫囵吞枣的,只要记住ReentrantLock和sychronized是可重入锁就行了,爱咋用咋用,好吧,原谅我的无知,最近对基础查漏补缺,发现竟然对其一问三不知,赶紧预习一波,觉得必要写一篇...
  • Java锁之可重入锁和递归锁

    千次阅读 2019-05-27 21:51:52
    Java锁之可重入锁和递归锁 目录 Java锁之可重入锁和递归锁基本概念 Java锁之可重入锁和递归锁代码验证 小结 理论,代码,小结,学习三板斧。 1. Java锁之可重入锁和递归锁基本概念 可重入锁(也...
  • 主要介绍了Java并发编程之重入锁与读写锁,文中相关实例代码详细,测试可用,具有一定参考价值,需要的朋友可以了解下。
  • 手写可重入锁

    2018-05-17 16:18:29
    java手写可重入锁,对刚学锁的同学很帮助,可以来下载互相学习一下。
  • Java synchronized 可重入锁 基本概念

    千次阅读 2017-02-07 19:04:58
    多线程 java几种方法可以实现一个线程?
  • Java 一些列锁公平锁与非公平锁可重入锁自旋锁读写锁 本文主要介绍Java的一些锁:公平锁,非公平锁,可重入锁,自旋锁,以及它们的使用案例 公平锁与非公平锁 公平锁就是多线程按照申请锁的顺序来获取锁,先来后到...
  • 主要介绍了java并发之重入锁-ReentrantLock,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • 锁分为可重入锁和不可重入锁重入和不重入的概念是这样的:当一个线程获得了当前实例的锁,并进入方法A,这个线程在没有释放这把锁的时候,能否再次进入方法A呢? 可重入锁:可以再次进入方法A,就是说在释放...
  • 转载:JAVA锁机制-可重入锁,中断锁,公平锁,读写锁,自旋锁,如果需要查看具体的synchronized和lock的实现原理,请参考:解决多线程安全问题-无非两个方法synchronized和lock 具体原理(百度) 在并发编程中,经常...
  • Java并发编程:自己动手写一把可重入锁

    千次阅读 多人点赞 2018-11-08 02:51:18
    现在来看一下什么是可重入锁可重入锁就是同一个线程多次尝试进入同步代码块的时候,能够顺利的进去并执行。实例代码如下: import java.util.concurrent.locks.Lock; import java.util.concurrent.locks....
  • java可重入锁ReentrantLock原理

    千次阅读 2018-04-01 15:10:42
    网上看到又去的故事阐述这个过程很有趣:轻松学习java可重入锁(ReentrantLock)的实现原理在一个村子里面,一口井水,水质非常的好,村民们都想打井里的水。这井只有一口,村里的人那么多,所以得出个打水的规则才...
  • 话说从前一个村子,在这个村子中一口水井,家家户户都需要到这口井里打水喝。由于井水有限,大家只能依次打水。为了实现家家水喝,户户水用的目标,村长绞尽脑汁,最终想出了一个比较合理的方案。 首先,在...
  • Java的ReentrantLock的源码实现,包括加锁、解锁的源码,以及公平性、重入性的实现!
  • Java可重入锁与其释放

    千次阅读 2017-08-26 20:45:25
    在学习Java多线程相关的知识时,通常都会涉及锁这个概念,常见的synchronized、Lock均为可重入锁。为了更好的理解可重入锁,需要先理解一下几个问题: 1、谁持有了锁? 2、锁的对象是谁? 3、可重入锁重入是...
  • Java 实现基于Redis的分布式可重入锁

    千次阅读 2016-09-28 21:48:52
    之前在 Java实现基于的Redis的分布式锁 这篇文章中,已经实现了加锁的逻辑,但是个缺点,就是不重入,任何重入锁的尝试都会导致死锁的发生,想了一下,这个问题可以解决。     Thinking   ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 99,944
精华内容 39,977
关键字:

java有哪些可重入锁

java 订阅