栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

java重入锁

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

java重入锁

一、重入锁理解
  • 某线程获取锁后,可以再次获取锁
  • synchronized 和 ReentrantLock 都是可重入锁
  • 可重入锁解决同一线程中内外层方法调用死锁的问题
二、可重入锁示例 1、synchronized 可重入锁演示
    
    private static void reLockSyncDemo(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (this){
                    System.out.println("第1次获取锁,当前锁是:" + this);
                    int index=0;
                    while(true){
                        synchronized (this){
                            System.out.println("第" + (++index) + "次获取重入锁,当前锁是:" + this);
                        }
                        if (index == 5) {
                            break;
                        }
                    }
                }
            }
        }).start();
    }

2、ReentronLock 可重入锁演示
 		
    private static void reentrantLockDemo(){
        ReentrantLock rl = new ReentrantLock();
        new Thread(new Runnable() {
            @Override
            public void run() {
                rl.lock();
                try {
                    System.out.println("第1次获取锁,当前锁是:" + rl);
                    int index = 0;
                    while (true) {
                        rl.lock();
                        try {
                            System.out.println("第" + (++index) + "次获取重入锁,当前锁是:" + rl);
                            if (index == 5) {
                                break;
                            }
                        } finally {
                            rl.unlock();
                        }
                    }
                }finally{
                    rl.unlock();
                }
            }
        }).start();
    }

ReentronLock 在多层可重入锁调用时,lock数必须与unlock数对等,否则会出现死锁

三、可重入锁简单实现
public class MyRelock implements Lock {

    //是否已经上锁
    private boolean isLocked = false;

    //记录当前线程
    Thread currThread = null;

    //记录当前锁数量
    private int lockNum = 0;

    @Override
    public void lock() {
        //获取当前线程
        Thread thread = Thread.currentThread();
        //当前已上锁 且 当前线程不是已上锁线程 进入循环等待
        while (isLocked && thread!= currThread ){
            try {
                Thread.sleep(50);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }

        // 锁状态置为true
        isLocked = true;
        // 记录当前线程
        currThread = thread;
        // 锁记录数 加一
        lockNum++;
    }


    @Override
    public void unlock() {
        // 判断是否为当前锁的线程
        if(Thread.currentThread()==currThread){
            // 锁记录 --
            lockNum--;
            if (lockNum == 0){
                isLocked = false;
            }
        }
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {

    }
    @Override
    public boolean tryLock() {
        return false;
    }
    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return false;
    }
    @Override
    public Condition newCondition() {
        return null;
    }

测试

MyRelock myRelock = new MyRelock();
    private static void testMyRelock(){
        Demo demo = new Demo();
        new Thread(new Runnable() {
            @Override
            public void run() {
                demo.functionA();
            }
        }).start();
    }

    private void functionA(){
        myRelock.lock();
        System.out.println("functionA 执行了,锁为:"+myRelock);
        functionB();
        myRelock.unlock();
    }

    private void functionB(){
        myRelock.lock();
        System.out.println("functionB 执行了,锁为:"+myRelock);
        myRelock.unlock();
    }

四、synchronized可重入实现原理

每一个锁关联一个线程持有者和一个计数器,当计数器为0时表示当前锁没有被任何线程持有,此时任何线程都可以获取锁并执行相应的代码;当某一个线程获取锁成功后,jvm就会记录当前次有锁的线程,并将计数器加1;此时其他线程请求当前锁,则需要等待,如果持有当前锁的线程再次请求当前锁,可以获得当前锁,并且计数器加1,当锁内容执行完成后,计数器减1,如果当前计数器为0时,则线程持有者置为null,此时释放锁,唤醒等待线程。

五 、ReentronLock 可重入实现
// 同步队列,是一个带头结点的双向链表,用于实现锁的语义
public abstract class AbstractQueuedSynchronizer
    extends AbstractOwnableSynchronizer
    implements java.io.Serializable {
  // 重入锁计数/许可证数量,在不同的锁中,使用方式有所不同
    private volatile int state;
  
 //CAS方式更新状态
  protected final boolean compareAndSetState(int expect, int update) {
        // See below for intrinsics setup to support this
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
    }
}


public class ReentrantLock implements Lock, java.io.Serializable {
  
    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;

        
        abstract void lock();

        
        // 申请一次非公平锁,返回值代表锁是否申请成功
        final boolean nonfairTryAcquire(int acquires) {
            // 获取生成锁的线程
            final Thread current = Thread.currentThread();
            // 当前许可证数量  当前锁状态
            int c = getState();
            // 如果锁没有被任何线程占用
            if (c == 0) {
                

                // 尝试更新许可证数量为acquires,返回true代表更新成功,即成功抢到了锁
                if (compareAndSetState(0, acquires)) {
                    // 设置当前线程为<占有者线程>
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            
            // 如果当前线程不是锁的占用者,直接返回false,代表抢锁失败,该线程需要去排队
            else if (current == getExclusiveOwnerThread()) {
                
                int nextc = c + acquires;
                // 更新许可证数量
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
        // 释放一次锁,返回值表示同步锁是否处于自由状态(无线程持有)
        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }
    }
}

上面是ReentronLock实现的部分代码## 一、重入锁理解

  • 某线程获取锁后,可以再次获取锁
  • synchronized 和 ReentrantLock 都是可重入锁
  • 可重入锁解决同一线程中内外层方法调用死锁的问题
二、可重入锁示例 1、synchronized 可重入锁演示
    
    private static void reLockSyncDemo(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (this){
                    System.out.println("第1次获取锁,当前锁是:" + this);
                    int index=0;
                    while(true){
                        synchronized (this){
                            System.out.println("第" + (++index) + "次获取重入锁,当前锁是:" + this);
                        }
                        if (index == 5) {
                            break;
                        }
                    }
                }
            }
        }).start();
    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mceqrTCf-1634629291378)(/Users/lewis/Library/Application Support/typora-user-images/image-20211018153755361.png)]

2、ReentronLock 可重入锁演示
 		
    private static void reentrantLockDemo(){
        ReentrantLock rl = new ReentrantLock();
        new Thread(new Runnable() {
            @Override
            public void run() {
                rl.lock();
                try {
                    System.out.println("第1次获取锁,当前锁是:" + rl);
                    int index = 0;
                    while (true) {
                        rl.lock();
                        try {
                            System.out.println("第" + (++index) + "次获取重入锁,当前锁是:" + rl);
                            if (index == 5) {
                                break;
                            }
                        } finally {
                            rl.unlock();
                        }
                    }
                }finally{
                    rl.unlock();
                }
            }
        }).start();
    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NeCrmrZm-1634629291379)(/Users/lewis/Library/Application Support/typora-user-images/image-20211018153908473.png)]

ReentronLock 在多层可重入锁调用时,lock数必须与unlock数对等,否则会出现死锁

三、可重入锁简单实现
public class MyRelock implements Lock {

    //是否已经上锁
    private boolean isLocked = false;

    //记录当前线程
    Thread currThread = null;

    //记录当前锁数量
    private int lockNum = 0;

    @Override
    public void lock() {
        //获取当前线程
        Thread thread = Thread.currentThread();
        //当前已上锁 且 当前线程不是已上锁线程 进入循环等待
        while (isLocked && thread!= currThread ){
            try {
                Thread.sleep(50);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }

        // 锁状态置为true
        isLocked = true;
        // 记录当前线程
        currThread = thread;
        // 锁记录数 加一
        lockNum++;
    }


    @Override
    public void unlock() {
        // 判断是否为当前锁的线程
        if(Thread.currentThread()==currThread){
            // 锁记录 --
            lockNum--;
            if (lockNum == 0){
                isLocked = false;
            }
        }
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {

    }
    @Override
    public boolean tryLock() {
        return false;
    }
    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return false;
    }
    @Override
    public Condition newCondition() {
        return null;
    }

测试

MyRelock myRelock = new MyRelock();
    private static void testMyRelock(){
        Demo demo = new Demo();
        new Thread(new Runnable() {
            @Override
            public void run() {
                demo.functionA();
            }
        }).start();
    }

    private void functionA(){
        myRelock.lock();
        System.out.println("functionA 执行了,锁为:"+myRelock);
        functionB();
        myRelock.unlock();
    }

    private void functionB(){
        myRelock.lock();
        System.out.println("functionB 执行了,锁为:"+myRelock);
        myRelock.unlock();
    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-24wCcr7q-1634629291380)(/Users/lewis/Library/Application Support/typora-user-images/image-20211018163405154.png)]

四、synchronized可重入实现原理

每一个锁关联一个线程持有者和一个计数器,当计数器为0时表示当前锁没有被任何线程持有,此时任何线程都可以获取锁并执行相应的代码;当某一个线程获取锁成功后,jvm就会记录当前次有锁的线程,并将计数器加1;此时其他线程请求当前锁,则需要等待,如果持有当前锁的线程再次请求当前锁,可以获得当前锁,并且计数器加1,当锁内容执行完成后,计数器减1,如果当前计数器为0时,则线程持有者置为null,此时释放锁,唤醒等待线程。

五 、ReentronLock 可重入实现
// 同步队列,是一个带头结点的双向链表,用于实现锁的语义
public abstract class AbstractQueuedSynchronizer
    extends AbstractOwnableSynchronizer
    implements java.io.Serializable {
  // 重入锁计数/许可证数量,在不同的锁中,使用方式有所不同
    private volatile int state;
  
 //CAS方式更新状态
  protected final boolean compareAndSetState(int expect, int update) {
        // See below for intrinsics setup to support this
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
    }
}


public class ReentrantLock implements Lock, java.io.Serializable {
  
    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;

        
        abstract void lock();

        
        // 申请一次非公平锁,返回值代表锁是否申请成功
        final boolean nonfairTryAcquire(int acquires) {
            // 获取生成锁的线程
            final Thread current = Thread.currentThread();
            // 当前许可证数量  当前锁状态
            int c = getState();
            // 如果锁没有被任何线程占用
            if (c == 0) {
                

                // 尝试更新许可证数量为acquires,返回true代表更新成功,即成功抢到了锁
                if (compareAndSetState(0, acquires)) {
                    // 设置当前线程为<占有者线程>
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            
            // 如果当前线程不是锁的占用者,直接返回false,代表抢锁失败,该线程需要去排队
            else if (current == getExclusiveOwnerThread()) {
                
                int nextc = c + acquires;
                // 更新许可证数量
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
        // 释放一次锁,返回值表示同步锁是否处于自由状态(无线程持有)
        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }
    }
}

上面是ReentronLock实现的部分代码

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/337254.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号