• 聊聊高并发(十六)实现一个简单的可重入锁


    可重入锁指的是假设一个线程已经获得了一个锁,那么它能够多次进入这个锁,当然前提是线程须要先获得这个锁。

    可重入锁是最常使用的锁。Java的内置锁就是可重入锁,使用synchronizedkeyword能够启用内置锁机制,比方说一个类有两个synchronized方法A和B。在A方法中调用了B方法,假设锁不是可重入的。那么訪问B时须要再次竞争锁。这样会带来死锁。

            public synchronized void A(){
    		B();
    	}
    	
    	public synchronized void B(){
    		
    	}


    可重入锁攻克了这个问题,它使用一个计数器来记录一个线程进入锁的次数,每次进入锁计数器就加1。释放锁减1。直到计数器为0时表示真正释放了锁。其它锁看到计数器不为0时就知道有其它线程已经获得了锁。就须要等待。Java的内置锁的基本原理也是这样,JDK1.5之后提供了显式锁ReentrantLock也是这个基本原理。


    以下实现一个简单的可重入锁。

    1. 使用一个Thread引用指向获得锁的线程

    2. 使用一个计数器记录一个线程进入锁的次数,当计数器为0时表示锁是空暇的

    3. 使用一个内部锁Lock来同步线程

    4. 使用一个isHoldZero的条件来进行条件队列操作

    5. 当获得锁的线程是自己时,仅仅改动计数器的值,直接获得锁

    6. 当获得锁的线程不是自己时。须要在holdCount !=0 这个条件谓词上等待。直到计数器归0,再次竞争锁

    7. 释放锁时计数器减1,当计数器为0时。唤醒在条件队列中等待的线程


    package com.zc.lock;
    
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.ReentrantLock;
    
    
    /**
     * 简单的可重入锁实现,使用一个计数器记录当前线程重入锁的次数,获得锁时计数器加1,释放锁时计数器减1。当计数器等于0时表示释放了锁
     * **/
    public class SimpleReentrantLock implements Lock{
        
        // 指向已经获得锁的线程
        private volatile Thread exclusiveOwnerThread;
        
        // 记录获取了同一个锁的次数
        private volatile int holdCount;
        
        private final java.util.concurrent.locks.Lock lock;
        
        // 是否是自己获得锁的条件
        private final Condition isCountZero;
        
        public SimpleReentrantLock(){
            lock = new ReentrantLock();
            isCountZero = lock.newCondition();
            holdCount = 0;
        }
        
        @Override
        public void lock() {
            lock.lock();
            try{
                // 当前线程的引用
                Thread currentThread = Thread.currentThread();
                // 假设获得锁的线程是自己,那么计数器加1,直接返回
                if(exclusiveOwnerThread == currentThread){
                    holdCount ++;
                    return;
                }
                
                while(holdCount != 0){
                    try {
                        isCountZero.await();
                    } catch (InterruptedException e) {
                        throw new RuntimeException("Interrupted");
                    }
                }
                // 将exclusiveOwnerThread设置为自己
                exclusiveOwnerThread = currentThread;
                holdCount ++;
            }finally{
                lock.unlock();
            }
        }
    
        @Override
        public void unlock() {
            lock.lock();
            try{
                holdCount --;
                if(holdCount == 0){
                    isCountZero.signalAll();
                }
            }finally{
                lock.unlock();
            }
        }
    
    }
    
    
    



  • 相关阅读:
    oracle 当行函数 日期
    veridata实验举例(1)验证TCUSTMER与TCUSTORD两节点同步情况
    sdut1730 数字三角形问题(dp入门题)
    Android4.0 Design之UI设计易犯的错误2
    怎样提高团队管理能力6
    Effective C++ 29-33
    内存补齐序列一:关于内存对齐和填充
    【 D3.js 入门系列 --- 10.1 】 简化 GeoJSON 文件
    Android TrafficStats类的使用
    新手上路:Laravel-控制器基础
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/5080648.html
Copyright © 2020-2023  润新知