• 可重入锁 与 不可重入锁


    可重入锁,也叫递归锁

     可重入锁:指的是同一个线程外层函数获得锁之后,内层递归函数仍然能获取该锁的代码,在同一个线程在外层方法获取锁的时候,进入内层方法会自动获取锁  

     种类:ReentrantLock 和 synchronized 都是可重入锁 

     作用:避免死锁 

    注意点:用了锁,一定要记得开锁和关锁,lock和unlock方法都是一对一对的出现,避免出现错误,如果少了其中的一个,就会报错。

    ReentrantLock  版本:

    复制代码
    public class MyLock_1 {
        
        public static void main(String[] args) {
            Mylock(); 
            new Thread(()->{
                Mylock();
            }).start();
        }
    
       static ReentrantLock reentrantLock = new ReentrantLock();
        public static void Mylock(){
            reentrantLock.lock();
            try {
                System.out.println("第一把锁:"+Thread.currentThread().getId());
                Lock lock = new ReentrantLock();
                lock.lock();
                try {
                    System.out.println("第二把锁:"+Thread.currentThread().getId());
                }finally {
                    lock.unlock();
                }
            }catch (Exception ex){
                ex.printStackTrace();
            }finally {
                reentrantLock.unlock();
            }
        }
    }
    复制代码
    结果:

    synchronized 版本:其实一层里面再套一层,多层,但是获取到的对象都是第一把锁,锁住的对象。
    复制代码
    public class Xttblog {
        public static void main(String[] args) {
            Xttblog child = new Xttblog();
            child.doSomething();
        }
     
        public synchronized void doSomething() {
            System.out.println("child.doSomething()" + Thread.currentThread().getName());
            doAnotherThing(); // 调用自己类中其他的synchronized方法
        }
     
        private synchronized void doAnotherThing() {
            super.doSomething(); // 调用父类的synchronized方法
            System.out.println("child.doAnotherThing()" + Thread.currentThread().getName());
        }
    }
     
    class SuperXttblog {
        public synchronized void doSomething() {
            System.out.println("father.doSomething()" + Thread.currentThread().getName());
        }
    }
    复制代码

    结果:

     可重入锁的原理 详情到时看 ReentrantLock 源码 

    重入锁实现可重入性原理或机制是:每一个锁关联一个线程持有者和计数器,当计数器为 0 时表示该锁没有被任何线程持有,那么任何线程都可能获得该锁而调用相应的方法;

    当某一线程请求成功后,JVM会记下锁的持有线程,并且将计数器置为 1;此时其它线程请求该锁,则必须等待;而该持有锁的线程如果再次请求这个锁,就可以再次拿到这个锁,

    同时计数器会递增;当线程退出同步代码块时,计数器会递减,如果计数器为 0,则释放该锁。


    不可重入锁:

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

    我们尝试设计一个不可重入锁 (参考网上大佬)

    package sss;
    
    public class myLock_2 {
        public static void main(String[] args) throws InterruptedException {
            new count().print();
        }
    }
    
    class count{
        //声明一把锁对象,全局锁
        Lock lock = new Lock();
        public void print() throws InterruptedException{
            lock.lock();
            doAdd();
            lock.unlock();
        }
    
        public void doAdd() throws InterruptedException {
            lock.lock(); //这里会因为得不到锁对象这里阻塞
            System.out.println("这是doAdd()");
            lock.unlock();
        }
    }
    
    class Lock{   //定义一把锁 
    
        private boolean isLocked = false;
    
        public synchronized void lock() throws InterruptedException {
            while (isLocked){
                wait();
            }
            isLocked = true;
        }
    
        public synchronized void unlock(){
            isLocked = false;
            notify();
        }
    }

    不可重入锁的本质: 由于线程之间的获取资源的加上了锁,却没有释放锁,导致程序的后面无法得到锁对象资源而出现了阻塞,其实也就是线程之间的通信出现了障碍。

  • 相关阅读:
    JS中的getter与setter
    Node.js中exports与module.exports的区别
    JS中的匿名函数自执行、函数声明与函数表达式
    JS实现千分位
    JS中的new操作符原理解析
    JS中null与undefined的区别
    JavaScript中callee与caller,apply与call解析
    解决vue路由与锚点冲突
    jQuery中deferred的对象使用
    Vue的生命周期
  • 原文地址:https://www.cnblogs.com/cb1186512739/p/12743902.html
Copyright © 2020-2023  润新知