JUC源码阅读-ReentrantLock

ReentrantLock可重入锁,是一种递归无阻塞的同步机制。它可以等同与synchornized实现同步。并且提供了比synchornized更为灵活的加锁机制。
ReentrantLock提供了公平锁FairSync和非公平锁NonfairSync两种机制。

 

  1. 公平锁,锁的获取是有序的
  2. 非公平锁,获取锁不是有序的,但效率比公平锁高,在多线程下,吞吐量较高。

ReentrantLock实现了Lock接口,内部基于Sync实现。

Sync类

Sync是ReentrantLock中的内部静态类,它继承了AbstractQueuedSynchronizer类,它使用AbstractQueuedSynchronizer类中state字段表示当前锁的持有数量,从而实现重入功能。其源码如下:

abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;

        /**
         * Performs {@link Lock#lock}. The main reason for subclassing
         * is to allow fast path for nonfair version.
         */
        //加锁
        abstract void lock();

        /**
         * Performs non-fair tryLock.  tryAcquire is implemented in
         * subclasses, but both need nonfair try for trylock method.
         */

        //非公平锁获取锁
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            //当前持有锁的数量
            int c = getState();
            //如果为0,说明是空闲状态
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    //将锁设置为当前线程所有。
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            //不是空闲状态,判断当前线程是否是持有锁的线程,如果是,线程重入,持有锁的数量 + acquires
            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;
            //如果减去持有锁数量后,同步状态为0,说明为空闲状态,设置为空闲状态
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            //设置持有数量
            setState(c);
            //返回是否释放成功
            return free;
        }

        //当前线程是否是以独占锁的方式运行的
        protected final boolean isHeldExclusively() {
            // While we must in general read state before owner,
            // we don't need to do so to check if current thread is owner
            return getExclusiveOwnerThread() == Thread.currentThread();
        }

        //Condition条件
        final ConditionObject newCondition() {
            return new ConditionObject();
        }

        // Methods relayed from outer class

        //当前持有锁的线程
        final Thread getOwner() {
            return getState() == 0 ? null : getExclusiveOwnerThread();
        }

        //当前持有锁的数量
        final int getHoldCount() {
            return isHeldExclusively() ? getState() : 0;
        }

        //是否有锁
        final boolean isLocked() {
            return getState() != 0;
        }

        /**
         * Reconstitutes the instance from a stream (that is, deserializes it).
         */
        private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
            s.defaultReadObject();
            setState(0); // reset to unlocked state
        }
    }

此段代码中重点关注非公平锁获取方式以及释放锁方法,非公平锁获取方式主要流程如下:

  1. 首先判断线程同步状态,如果为0,说明是空闲状态,就将锁设置为当前线程所有。
  2. 如果部位0,判断当前线程是否是持有锁的线程,如果是,则是线程重入,将持有锁的数量 + acquires,实现线程重入的特性。
  3. 如果获取到锁,返回true,否则返回false.

释放锁流程如下:

  1. 首先将state减去release;
  2. 判断当前线程是否是持有锁的线程,如果不是则抛出异常。
  3. 判断state是否为0,为0说明锁为空闲状态,将锁持有的线程设置为努力了,其他线程就可以获取同步状态了。
  4. 同步状态释放成功,则返回true,否则返回false.

 

NonfairSync类

NonfairSync 是 ReentrantLock 的内部静态类,实现 Sync 抽象类,是非公平锁实现类。其源码如下:

static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;

        /**
         * Performs lock.  Try immediate barge, backing up to normal
         * acquire on failure.
         */
        //实现Sync类的lock方法
        final void lock() {
            //CAS ,如果设置状态成功,将当前线程设置为持有锁线程
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                //失败,尝试获取锁,此方法在AbstractQueuedSynchronizer中。
                acquire(1);
        }
        
        //重写AbstractQueuedSynchronizer类的tryAcquire方法
        protected final boolean tryAcquire(int acquires) {
            //非公平锁获取
            return nonfairTryAcquire(acquires);
        }
    }

FairSync类

NonfairSync 是 ReentrantLock 的内部静态类,实现 Sync 抽象类,是公平锁实现类。其源码如下:

static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;

        //公平锁获取
        final void lock() {
            acquire(1);
        }

        /**
         * Fair version of tryAcquire.  Don't grant access unless
         * recursive call or no waiters or is first.
         */
        //重写AQS的方法,尝试获取公平锁
        protected final boolean tryAcquire(int acquires) {

            final Thread current = Thread.currentThread();
            int c = getState();
            //当前锁为空闲状态
            if (c == 0) {
                //判断当前等待节点是否有前序节点,即自己不是首个等待获取锁的节点。
                //设置状态
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    //设置锁线程为当前线程。
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            //判断当前线程是否是锁线程
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
    }

公平锁获取方式比非公平锁获取方式多了一个hasQueuedPredecessors方法,此方法在AQS类中,主要作用是判断当前线程节点是否有前置等待获取锁的线程节点。其源码如下:

//该方法主要是判断当前线程是否位于 CLH 同步队列中的第一个。如果是则返回 true ,否则返回 false 。
public final boolean hasQueuedPredecessors() {
        // The correctness of this depends on head being initialized
        // before tail and on head.next being accurate if the current
        // thread is first in queue.
        Node t = tail; // Read fields in reverse initialization order
        Node h = head;
        Node s;
        return h != t &&
            ((s = h.next) == null || s.thread != Thread.currentThread());
    }

ReentrantLock

ReentrantLock的实现方法,基本上是对Syncnn内部类的调用,其主要方法包括以下几个:

  1. ReentrantLock()无参构造,创建一个非公平锁的重入锁。
  2. ReentrantLock(boolean fair) 根据fair创建一个重入锁,fair为true为公平锁,false为非公平锁。
  3. lock() 获取锁。
  4. tryLock()尝试获取锁。
  5. unLock()释放锁。
  6. newCondition()条件。

源码:

//创建非公平锁
 public ReentrantLock() {
        sync = new NonfairSync();
    }

    //根据fair创建公平锁或非公平锁
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

    //获取锁,立即返回
    public void lock() {
        sync.lock();
    }
//尝试获取锁,实现时,希望快速获取锁,所以即使fair= true即为公平锁的情况下依然使用非公平锁获取的实现。
public boolean tryLock() {
        return sync.nonfairTryAcquire(1);
    }
//带有超时 的获取锁,此方法按照fair实现的方式获取锁。
    public boolean tryLock(long timeout, TimeUnit unit)
            throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }

//释放锁
public void unlock() {
        sync.release(1);
    }

      //Condition条件
        final ConditionObject newCondition() {
            return new ConditionObject();
        }

注:tryLock()方法在使用时,即使时公平锁的实现,也会调用非公平锁的方法快速获取锁。这也是nonfairTyrAcquire()方法在Sync写在Sync而非NonfairSync中的原因。

ReentrantLock和Synchronized的区别

ReentrantLoc和synchronized两者都能够实现线程通过,两者之间的区别主要在以下几个方面:

  1. 与 synchronized 相比,ReentrantLock提供了更多,更加全面的功能,具备更强的扩展性。例如:时间锁等候,可中断锁等候,锁投票。
  2. ReentrantLock 还提供了条件 Condition ,对线程的等待、唤醒操作更加详细和灵活,所以在多个条件变量和高度竞争锁的地方,ReentrantLock 更加适合。
  3. ReentrantLock 提供了可轮询的锁请求。它会尝试着去获取锁,如果成功则继续,否则可以等到下次运行时处理,而 synchronized 则一旦进入锁请求要么成功要么阻塞,所以相比 synchronized 而言,ReentrantLock会不容易产生死锁些。
  4. ReentrantLock 支持更加灵活的同步代码块,但是使用 synchronized 时,只能在同一个 synchronized 块结构中获取和释放。注意,ReentrantLock 的锁释放一定要在 finally 中处理,否则可能会产生严重的后果。
  5. ReentrantLock 支持中断处理,且性能较 synchronized 会好些。

此段来自芋道源码【死磕 Java 并发】—– J.U.C 之重入锁:ReentrantLock 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
4S店客户管理小程序-毕业设计,基于微信小程序+SSM+MySql开发,源码+数据库+论文答辩+毕业论文+视频演示 社会的发展和科学技术的进步,互联网技术越来越受欢迎。手机也逐渐受到广大人民群众的喜爱,也逐渐进入了每个用户的使用。手机具有便利性,速度快,效率高,成本低等优点。 因此,构建符合自己要求的操作系统是非常有意义的。 本文从管理员、用户的功能要求出发,4S店客户管理系统中的功能模块主要是实现管理员服务端;首页、个人中心、用户管理、门店管理、车展管理、汽车品牌管理、新闻头条管理、预约试驾管理、我的收藏管理、系统管理,用户客户端:首页、车展、新闻头条、我的。门店客户端:首页、车展、新闻头条、我的经过认真细致的研究,精心准备和规划,最后测试成功,系统可以正常使用。分析功能调整与4S店客户管理系统实现的实际需求相结合,讨论了微信开发者技术与后台结合java语言和MySQL数据库开发4S店客户管理系统的使用。 关键字:4S店客户管理系统小程序 微信开发者 Java技术 MySQL数据库 软件的功能: 1、开发实现4S店客户管理系统的整个系统程序; 2、管理员服务端;首页、个人中心、用户管理、门店管理、车展管理、汽车品牌管理、新闻头条管理、预约试驾管理、我的收藏管理、系统管理等。 3、用户客户端:首页、车展、新闻头条、我的 4、门店客户端:首页、车展、新闻头条、我的等相应操作; 5、基础数据管理:实现系统基本信息的添加、修改及删除等操作,并且根据需求进行交流信息的查看及回复相应操作。
现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本微信小程序医院挂号预约系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息,使用这种软件工具可以帮助管理人员提高事务处理效率,达到事半功倍的效果。此微信小程序医院挂号预约系统利用当下成熟完善的SSM框架,使用跨平台的可开发大型商业网站的Java语言,以及最受欢迎的RDBMS应用软件之一的MySQL数据库进行程序开发。微信小程序医院挂号预约系统有管理员,用户两个角色。管理员功能有个人中心,用户管理,医生信息管理,医院信息管理,科室信息管理,预约信息管理,预约取消管理,留言板,系统管理。微信小程序用户可以注册登录,查看医院信息,查看医生信息,查看公告资讯,在科室信息里面进行预约,也可以取消预约。微信小程序医院挂号预约系统的开发根据操作人员需要设计的界面简洁美观,在功能模块布局上跟同类型网站保持一致,程序在实现基本要求功能时,也为数据信息面临的安全问题提供了一些实用的解决方案。可以说该程序在帮助管理者高效率地处理工作事务的同时,也实现了数据信息的整体化,规范化与自动化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值