Java源码解析之可重入锁ReentrantLock

本文基于jdk1.8进行分析。

ReentrantLock是一个可重入锁,在ConcurrentHashMap中使用了ReentrantLock。

首先看一下源码中对ReentrantLock的介绍。如下图。ReentrantLock是一个可重入的排他锁,它和synchronized的方法和代码有着相同的行为和语义,但有更多的功能。ReentrantLock是被最后一个成功lock锁并且还没有unlock的线程拥有着。如果锁没有被别的线程拥有,那么一个线程调用lock方法,就会成功获取锁并返回。如果当前线程已经拥有该锁,那么lock方法会立刻返回。这个可以通过isHeldByCurrentThread方法和getHoldCount方法进行验证。除了这部分介绍外,类前面的javadoc文档很长,就不在这里全部展开。随着后面介绍源码,会一一涉及到。

/**
 * A reentrant mutual exclusion {@link Lock} with the same basic
 * behavior and semantics as the implicit monitor lock accessed using
 * {@code synchronized} methods and statements, but with extended
 * capabilities.
 * <p>A {@code ReentrantLock} is <em>owned</em> by the thread last
 * successfully locking, but not yet unlocking it. A thread invoking
 * {@code lock} will return, successfully acquiring the lock, when
 * the lock is not owned by another thread. The method will return
 * immediately if the current thread already owns the lock. This can
 * be checked using methods {@link #isHeldByCurrentThread}, and {@link
 * #getHoldCount}.

首先看一下成员变量,如下图。ReentrantLock只有一个成员变量sync,即同步器,这个同步器提供所有的机制。Sync是AbstractQueuedSynchronizer的子类,同时,Sync有2个子类,NonfairSync和FairSync,分别是非公平锁和公平锁。Sync,NonfaireSync和FairSync的具体实现后面再讲。

  /** Synchronizer providing all implementation mechanics **/
  private final Sync sync;

下面看一下构造函数。如下图。可以看到,ReentrantLock默认是非公平锁,它可以通过参数,指定初始化为公平锁或非公平锁。

  /**
   * Creates an instance of {@code ReentrantLock}.
   * This is equivalent to using {@code ReentrantLock(false)}.
   **/
  public ReentrantLock() {
    sync = new NonfairSync();
  }
  /**
   * Creates an instance of {@code ReentrantLock} with the
   * given fairness policy.
   * @param fair {@code true} if this lock should use a fair ordering policy
   **/
  public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
  }

下面看一下ReentrantLock的主要方法。首先是lock方法。如下图。lock方法的实现很简单,就是调用Sync的lock方法。而Sync的lock方法是个抽象的,具体实现在NonfairSync和FairSync中。这里我们先不展开讲,而是先读一下lock方法的注释,看看它的作用。lock方法的作用是获取该锁。分为3种情况。

1,如果锁没有被别的线程占有,那么当前线程就可以获取到锁并立刻返回,并把锁计数设置为1。

2,如果当前线程已经占有该锁了,那么就会把锁计数加1,立刻返回。

3,如果锁被另一个线程占有了,那么当前线程就无法再被线程调度,并且开始睡眠,直到获取到锁,在获取到到锁时,会把锁计数设置为1。

lockInterruptibly方法与lock功能类似,但lockInterruptibly方法在等待的过程中,可以响应中断。

  /**
   * Acquires the lock.
   * <p>Acquires the lock if it is not held by another thread and returns
   * immediately, setting the lock hold count to one.
   * <p>If the current thread already holds the lock then the hold
   * count is incremented by one and the method returns immediately.
   * <p>If the lock is held by another thread then the
   * current thread becomes disabled for thread scheduling
   * purposes and lies dormant until the lock has been acquired,
   * at which time the lock hold count is set to one.
   **/
  public void lock() {
    sync.lock();
  }
  public void lockInterruptibly() throws InterruptedException {
    sync.acquireInterruptibly(1);
  }

下面,详细看一下非公平锁和公平锁中对lock函数的实现。如下图。下图同时列出了公平锁和非公平锁中lock的实现逻辑。从注释和代码逻辑中,都可以看出,非公平锁进行lock时,先尝试立刻闯入(抢占),如果成功,则获取到锁,如果失败,再执行通常的获取锁的行为,即acquire(1)。

    /**
     * 非公平锁中的lock
     * Performs lock. Try immediate barge, backing up to normal
     * acquire on failure.
     **/
    final void lock() {
      if (compareAndSetState(0, 1))
        setExclusiveOwnerThread(Thread.currentThread());
      else
        acquire(1);
    }
    //公平锁中的lock
    final void lock() {
      acquire(1);
    }

那么,我们首先了解下,非公平锁“尝试立刻闯入”,究竟做了什么。稍后再继续讲解通常的获取锁的行为。下图是立即闯入行为compareAndSetState(0, 1)的实现。从compareAndSetState函数的注释中,可以知道,如果同步状态值与期望值相等,那么就把它的值设置为updated值。否则同步状态值与期望值不相等,则返回false。这个操作和volatile有着相同的内存语义,也就是说,这个操作对其他线程是可见的。compareAndSetState函数注释里描述的功能,是通过unsafe.compareAndSwapInt方法实现的,而unsafe.compareAndSwapInt是一个native方法,是用c++实现的。那么继续追问,c++底层是怎么实现的?C++底层是通过CAS指令来实现的。什么是CAS指令呢?来自维基百科的解释是,CAS,比较和交换,Compare and Swap,是用用于实现多线程原子同步的指令。它将内存位置的内容和给定值比较,只有在相同的情况下,将该内存的值设置为新的给定值。这个操作是原子操作。那么继续追问,CAS指令的原子性,是如何实现的呢?我们都知道指令时CPU来执行的,在多CPU系统中,内存是共享的,内存和多个cpu都挂在总线上,当一个CPU执行CAS指令时,它会先将总线LOCK位点设置为高电平。如果别的CPU也要执行CAS执行,它会发现总线LOCK位点已经是高电平了,则无法执行CAS执行。CPU通过LOCK保证了指令的原子执行。

现在来看一下非公平锁的lock行为,compareAndSetState(0, 1),它期望锁状态为0,即没有别的线程占用,并把新状态设置为1,即标记为占用状态。如果成功,则非公平锁成功抢到锁,之后setExclusiveOwnerThread,把自己设置为排他线程。非公平锁这小子太坏了。如果抢占失败,则执行与公平锁相同的操作。

  /**
   * Atomically sets synchronization state to the given updated
   * value if the current state value equals the expected value.
   * This operation has memory semantics of a {@code volatile} read
   * and write.
   * @param expect the expected value
   * @param update the new value
   * @return {@code true} if successful. False return indicates that the actual
   *     value was not equal to the expected value.
   **/
  protected final boolean compareAndSetState(int expect, int update) {
    // See below for intrinsics setup to support this
    return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
  }
  public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

下面看一下公平锁获取锁时的行为。如下图。这部分的逻辑有些多,请阅读代码中的注释进行理解。

  /**
   * 公平锁的lock
   **/
  final void lock() {
    acquire(1);
  }
  /**
   * Acquires in exclusive mode, ignoring interrupts. Implemented
   * by invoking at least once {@link #tryAcquire},
   * returning on success. Otherwise the thread is queued, possibly
   * repeatedly blocking and unblocking, invoking {@link
   * #tryAcquire} until success. This method can be used
   * to implement method {@link Lock#lock}.
   * @param arg the acquire argument. This value is conveyed to
   *    {@link #tryAcquire} but is otherwise uninterpreted and
   *    can represent anything you like.
   **/
  public final void acquire(int arg) {
    /**
     * acquire首先进行tryAcquire()操作。如果tryAcquire()成功时则获取到锁,即刻返回。
     * 如果tryAcquire()false时,会执行acquireQueued(addWaiter(Node.EXCLUSIVE), arg)
     * 操作。如果acquireQueued(addWaiter(Node.EXCLUSIVE), arg)true时,则当前线程中断自己。
     * 如果acquireQueued(addWaiter(Node.EXCLUSIVE), arg)false,则返回。
     * 其中tryAcquire()操作在NonfairSync中和FairSync中实现又有所区别。
     **/
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
      selfInterrupt();
  }
  /**
   * NonfairSync中的tryAcquire。
   * @param acquires
   * @return
   **/
  protected final boolean tryAcquire(int acquires) {
    return nonfairTryAcquire(acquires);
  }
  /**
   * 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();
    if (c == 0) {
      //c为0,表示目前没有线程占用锁。没有线程占用锁时,当前线程尝试抢锁,如果抢锁成功,则返回true。
      if (compareAndSetState(0, acquires)) {
        setExclusiveOwnerThread(current);
        return true;
      }
    }
    else if (current == getExclusiveOwnerThread()) {
      //c不等于0时表示锁被线程占用。如果是当前线程占用了,则将锁计数加上acquires,并返回true。
      int nextc = c + acquires;
      if (nextc < 0) // overflow
        throw new Error("Maximum lock count exceeded");
      setState(nextc);
      return true;
    }
    //以上情况都不是时,返回false,表示非公平抢锁失败。
    return false;
  }
  /**
   * Fair version of tryAcquire. Don't grant access unless
   * recursive call or no waiters or is first.
   * 这个是公平版本的tryAcquire
   **/
  protected final boolean tryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
      //c=0时表示锁未被占用。这里是先判断队列中前面是否有别的线程。没有别的线程时,才进行CAS操作。
      //公平锁之所以公平,正是因为这里。它发现锁未被占用时,首先判断等待队列中是否有别的线程已经在等待了。
      //而非公平锁,发现锁未被占用时,根本不管队列中的排队情况,上来就抢。
      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;
  }
  /**
   * Acquires in exclusive uninterruptible mode for thread already in
   * queue. Used by condition wait methods as well as acquire.
   * 当抢锁失败时,先执行addWaiter(Node.EXCLUSIVE),将当前线程加入等待队列,再执行该方法。
   * 该方法的作用是中断当前线程,并进行检查,知道当前线程是队列中的第一个线程,并且抢锁成功时,
   * 该方法返回。
   * @param node the node
   * @param arg the acquire argument
   * @return {@code true} if interrupted while waiting
   **/
  final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
      boolean interrupted = false;
      for (;;) {
        final Node p = node.predecessor();
        if (p == head && tryAcquire(arg)) {
          setHead(node);
          p.next = null; // help GC
          failed = false;
          return interrupted;
        }
        if (shouldParkAfterFailedAcquire(p, node) &&
            parkAndCheckInterrupt())
          interrupted = true;
      }
    } finally {
      if (failed)
        cancelAcquire(node);
    }
  }

接下来是tryLock方法。代码如下。从注释中我们可以理解到,只有当调用tryLock时锁没有被别的线程占用,tryLock才会获取锁。如果锁没有被另一个线程占用,那么就获取锁,并立刻返回true,并把锁计数设置为1. 甚至在锁被设置为公平排序的情况下,若果锁可用,调用tryLock会立刻获取锁,而不管有没有别的线程在等待锁了。从这里我们总结出,不管可重入锁是公平锁还是非公平锁,tryLock方法只会是非公平的。

/**
   * Acquires the lock only if it is not held by another thread at the time
   * of invocation.
   * <p>Acquires the lock if it is not held by another thread and
   * returns immediately with the value {@code true}, setting the
   * lock hold count to one. Even when this lock has been set to use a
   * fair ordering policy, a call to {@code tryLock()} <em>will</em>
   * immediately acquire the lock if it is available, whether or not
   * other threads are currently waiting for the lock.
   * This "barging" behavior can be useful in certain
   * circumstances, even though it breaks fairness. If you want to honor
   * the fairness setting for this lock, then use
   * {@link #tryLock(long, TimeUnit) tryLock(0, TimeUnit.SECONDS) }
   * which is almost equivalent (it also detects interruption).
   * <p>If the current thread already holds this lock then the hold
   * count is incremented by one and the method returns {@code true}.
   * <p>If the lock is held by another thread then this method will return
   * immediately with the value {@code false}.
   * @return {@code true} if the lock was free and was acquired by the
   *     current thread, or the lock was already held by the current
   *     thread; and {@code false} otherwise
   **/
  public boolean tryLock() {
    return sync.nonfairTryAcquire(1);
  }
  public boolean tryLock(long timeout, TimeUnit unit)
      throws InterruptedException {
    return sync.tryAcquireNanos(1, unit.toNanos(timeout));
  }

接下来是释放锁的方法unlock。代码如下。unlock方式的实现,是以参数1来调用sync.release方法。而release方法是如何实现的呢?release方法首先会调用tryRelease方法,如果tryRelease成功,则唤醒后继者线程。而tryRelease的实现过程十分清晰,首先获取锁状态,锁状态减去参数(放锁次数),得到新状态。然后判断持有锁的线程是否为当前线程,如果不是当前线程,则抛出IllegalMonitorStateException。然后判断,如果新状态为0,说明放锁成功,则把持有锁的线程设置为null,并返回true。如果新状态不为0,则返回false。从tryRelease的返回值来看,它返回的true或false,指的是否成功的释放了该锁。成功的释放该锁的意思是彻底释放锁,别的线程就可以获取锁了。这里要认识到,即便tryRelease返回false,它也只是说明了锁没有完全释放,本次调用的这个释放次数值,依然是释放成功的。


  /**
   * Attempts to release this lock.
   * <p>If the current thread is the holder of this lock then the hold
   * count is decremented. If the hold count is now zero then the lock
   * is released. If the current thread is not the holder of this
   * lock then {@link IllegalMonitorStateException} is thrown.
   * @throws IllegalMonitorStateException if the current thread does not
   *     hold this lock
   **/
  public void unlock() {
    sync.release(1);
  }
  /**
   * Releases in exclusive mode. Implemented by unblocking one or
   * more threads if {@link #tryRelease} returns true.
   * This method can be used to implement method {@link Lock#unlock}.
   * @param arg the release argument. This value is conveyed to
   *    {@link #tryRelease} but is otherwise uninterpreted and
   *    can represent anything you like.
   * @return the value returned from {@link #tryRelease}
   **/
  public final boolean release(int arg) {
    if (tryRelease(arg)) {
      Node h = head;
      if (h != null && h.waitStatus != 0)
        unparkSuccessor(h);
      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;
    }
  /**
   * Wakes up node's successor, if one exists.
   * @param node the node
   **/
  private void unparkSuccessor(Node node) {
    /**
     * If status is negative (i.e., possibly needing signal) try
     * to clear in anticipation of signalling. It is OK if this
     * fails or if status is changed by waiting thread.
     **/
    int ws = node.waitStatus;
    if (ws < 0)
      compareAndSetWaitStatus(node, ws, 0);
    /**
     * Thread to unpark is held in successor, which is normally
     * just the next node. But if cancelled or apparently null,
     * traverse backwards from tail to find the actual
     * non-cancelled successor.
     **/
    Node s = node.next;
    if (s == null || s.waitStatus > 0) {
      s = null;
      for (Node t = tail; t != null && t != node; t = t.prev)
        if (t.waitStatus <= 0)
          s = t;
    }
    if (s != null)
      LockSupport.unpark(s.thread);
  }

接下来是newCondition方法。关于Condition这里不展开介绍,只是了解下该方法的作用。如下图。该方法返回一个和这个锁实例一起使用的Condition实例。返回的Condition实例支持和Object的监控方法例如wait-notify和notifyAll相同的用法。

  • 1,如果没有获取锁,调用Condition的await,signal,signalAll方法的任何一个时,会抛出IllegalMonitorStateException异常。
  • 2,调用Condition的await方法时,锁也会释放,在await返回之前,锁会被重新获取,并且锁计数会恢复到调用await方法时的值。
  • 3,如果一个线程在等待的过程中被中断了,那么等待就会结束,并抛出InterruptedException异常,线程的中断标志位会被清理。
  • 4,等待的线程以FIFO的顺序被唤醒。
  • 5,从await方法返回的线程们的获取到锁的顺序,和线程最开始获取锁的顺序相同,这是未指定情况下的默认实现。但是,公平锁更钟爱那些已经等待了最长时间的线程。
  /**
   * Returns a {@link Condition} instance for use with this
   * {@link Lock} instance.
   * <p>The returned {@link Condition} instance supports the same
   * usages as do the {@link Object} monitor methods ({@link
   * Object#wait() wait}, {@link Object#notify notify}, and {@link
   * Object#notifyAll notifyAll}) when used with the built-in
   * monitor lock.
   * <ul>
   * <li>If this lock is not held when any of the {@link Condition}
   * {@linkplain Condition#await() waiting} or {@linkplain
   * Condition#signal signalling} methods are called, then an {@link
   * IllegalMonitorStateException} is thrown.
   * <li>When the condition {@linkplain Condition#await() waiting}
   * methods are called the lock is released and, before they
   * return, the lock is reacquired and the lock hold count restored
   * to what it was when the method was called.
   * <li>If a thread is {@linkplain Thread#interrupt interrupted}
   * while waiting then the wait will terminate, an {@link
   * InterruptedException} will be thrown, and the thread's
   * interrupted status will be cleared.
   * <li> Waiting threads are signalled in FIFO order.
   * <li>The ordering of lock reacquisition for threads returning
   * from waiting methods is the same as for threads initially
   * acquiring the lock, which is in the default case not specified,
   * but for <em>fair</em> locks favors those threads that have been
   * waiting the longest.
   * </ul>
   * @return the Condition object
   **/
  public Condition newCondition() {
    return sync.newCondition();
  }

可重入锁还有一些其他的方法,这里就不一一介绍了。This is the end.

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。如果你想了解更多相关内容请查看下面相关链接

(0)

相关推荐

  • Java中的显示锁ReentrantLock使用与原理详解

    考虑一个场景,轮流打印0-100以内的技术和偶数.通过使用 synchronize 的 wait,notify机制就可以实现,核心思路如下: 使用两个线程,一个打印奇数,一个打印偶数.这两个线程会共享一个数据,数据每次自增,当打印奇数的线程发现当前要打印的数字不是奇数时,执行等待,否则打印奇数,并将数字自增1,对于打印偶数的线程也是如此 //打印奇数的线程 private static class OldRunner implements Runnable{ private MyNumber n

  • Java多线程中ReentrantLock与Condition详解

    一.ReentrantLock类 1.1什么是reentrantlock java.util.concurrent.lock中的Lock框架是锁定的一个抽象,它允许把锁定的实现作为Java类,而不是作为语言的特性来实现.这就为Lock的多种实现留下了空间,各种实现可能有不同的调度算法.性能特性或者锁定语义.ReentrantLock类实现了Lock,它拥有与synchronized相同的并发性和内存语义,但是添加了类似锁投票.定时锁等候和可中断锁等候的一些特性.此外,它还提供了在激烈争用情况下更

  • java ReentrantLock详解

    介绍 ReentrantLock称为重入锁,比内部锁synchonized拥有更强大的功能,它可中断.可定时.设置公平锁 [注]使用ReentrantLock时,一定要释放锁,一般释放放到finnal里写. 提供以下重要的方法 lock():获得锁,如果锁已被占用,则等待 lockInterruptibly():获得锁,但有限响应中断 unlock():释放锁 tryLock():尝试获取锁.如果获得,返回true:否则返回false tryLock(long time, TimeUnit un

  • Java并发系列之ReentrantLock源码分析

    在Java5.0之前,协调对共享对象的访问可以使用的机制只有synchronized和volatile.我们知道synchronized关键字实现了内置锁,而volatile关键字保证了多线程的内存可见性.在大多数情况下,这些机制都能很好地完成工作,但却无法实现一些更高级的功能,例如,无法中断一个正在等待获取锁的线程,无法实现限定时间的获取锁机制,无法实现非阻塞结构的加锁规则等.而这些更灵活的加锁机制通常都能够提供更好的活跃性或性能.因此,在Java5.0中增加了一种新的机制:Reentrant

  • 深入理解java内置锁(synchronized)和显式锁(ReentrantLock)

    synchronized 和 Reentrantlock 多线程编程中,当代码需要同步时我们会用到锁.Java为我们提供了内置锁(synchronized)和显式锁(ReentrantLock)两种同步方式.显式锁是JDK1.5引入的,这两种锁有什么异同呢?是仅仅增加了一种选择还是另有其因?本文为您一探究竟. // synchronized关键字用法示例 public synchronized void add(int t){// 同步方法 this.v += t; } public stati

  • Java并发之ReentrantLock类源码解析

    ReentrantLock内部由Sync类实例实现. Sync类定义于ReentrantLock内部. Sync继承于AbstractQueuedSynchronizer. AbstractQueuedSynchronizer继承于AbstractOwnableSynchronizer. AbstractOwnableSynchronizer类中只定义了一个exclusiveOwnerThread变量,表示当前拥有的线程. 除了Sync类,ReentrantLock内部还定义了两个实现类. No

  • 详解Java多线程编程中互斥锁ReentrantLock类的用法

    0.关于互斥锁 所谓互斥锁, 指的是一次最多只能有一个线程持有的锁. 在jdk1.5之前, 我们通常使用synchronized机制控制多个线程对共享资源的访问. 而现在, Lock提供了比synchronized机制更广泛的锁定操作, Lock和synchronized机制的主要区别: synchronized机制提供了对与每个对象相关的隐式监视器锁的访问, 并强制所有锁获取和释放均要出现在一个块结构中, 当获取了多个锁时, 它们必须以相反的顺序释放. synchronized机制对锁的释放是

  • Java并发编程之显示锁ReentrantLock和ReadWriteLock读写锁

    在Java5.0之前,只有synchronized(内置锁)和volatile. Java5.0后引入了显示锁ReentrantLock. ReentrantLock概况 ReentrantLock是可重入的锁,它不同于内置锁, 它在每次使用都需要显示的加锁和解锁, 而且提供了更高级的特性:公平锁, 定时锁, 有条件锁, 可轮询锁, 可中断锁. 可以有效避免死锁的活跃性问题.ReentrantLock实现了 Lock接口: 复制代码 代码如下: public interface Lock {  

  • 详解java并发之重入锁-ReentrantLock

    前言 目前主流的锁有两种,一种是synchronized,另一种就是ReentrantLock,JDK优化到现在目前为止synchronized的性能已经和重入锁不分伯仲了,但是重入锁的功能和灵活性要比这个关键字多的多,所以重入锁是可以完全替代synchronized关键字的.下面就来介绍这个重入锁. 正文 ReentrantLock重入锁是Lock接口里最重要的实现,也是在实际开发中应用最多的一个,我这篇文章更接近实际开发的应用场景,为开发者提供直接上手应用.所以不是所有方法我都讲解,有些冷门

  • Java源码解析之可重入锁ReentrantLock

    本文基于jdk1.8进行分析. ReentrantLock是一个可重入锁,在ConcurrentHashMap中使用了ReentrantLock. 首先看一下源码中对ReentrantLock的介绍.如下图.ReentrantLock是一个可重入的排他锁,它和synchronized的方法和代码有着相同的行为和语义,但有更多的功能.ReentrantLock是被最后一个成功lock锁并且还没有unlock的线程拥有着.如果锁没有被别的线程拥有,那么一个线程调用lock方法,就会成功获取锁并返回.

  • Java源码解析重写锁的设计结构和细节

    目录 引导语 1.需求 2.详细设计 2.1.定义锁 2.2.定义同步器Sync 2.3.通过能否获得锁来决定能否得到链接 3.测试 4.总结 引导语 有的面试官喜欢让同学在说完锁的原理之后,让你重写一个新的锁,要求现场在白板上写出大概的思路和代码逻辑,这种面试题目,蛮难的,我个人觉得其侧重点主要是两个部分: 考察一下你对锁原理的理解是如何来的,如果你对源码没有解读过的话,只是看看网上的文章,或者背面试题,也是能够说出大概的原理,但你很难现场写出一个锁的实现代码,除非你真的看过源码,或者有和锁相

  • Java源码解析之详解ReentrantLock

    ReentrantLock ReentrantLock是一种可重入的互斥锁,它的行为和作用与关键字synchronized有些类似,在并发场景下可以让多个线程按照一定的顺序访问同一资源.相比synchronized,ReentrantLock多了可扩展的能力,比如我们可以创建一个名为MyReentrantLock的类继承ReentrantLock,并重写部分方法使其更加高效. 当一个线程调用ReentrantLock.lock()方法时,如果ReentrantLock没有被其他线程持有,且不存在

  • Java源码解析之超级接口Map

    前言 我们在前面说到的无论是链表还是数组,都有自己的优缺点,数组查询速度很快而插入很慢,链表在插入时表现优秀但查询无力.哈希表则整合了数组与链表的优点,能在插入和查找等方面都有不错的速度.我们之后要分析的HashMap就是基于哈希表实现的,不过在JDK1.8中还引入了红黑树,其性能进一步提升了. 今天我们来说一说超级接口Map. 一.接口Map Map是基于Key-Value的数据格式,并且key值不能重复,每个key对应的value值唯一.Map的key也可以为null,但不可重复. 在看Ma

  • Java源码解析之ConcurrentHashMap

    早期 ConcurrentHashMap,其实现是基于: 分离锁,也就是将内部进行分段(Segment),里面则是 HashEntry 的数组,和 HashMap 类似,哈希相同的条目也是以链表形式存放. HashEntry 内部使用 volatile 的 value 字段来保证可见性,也利用了不可变对象的机制以改进利用 Unsafe 提供的底层能力,比如 volatile access,去直接完成部分操作,以最优化性能,毕竟 Unsafe 中的很多操作都是 JVM intrinsic 优化过的

  • Java源码解析之TypeVariable详解

    TypeVariable,类型变量,描述类型,表示泛指任意或相关一类类型,也可以说狭义上的泛型(泛指某一类类型),一般用大写字母作为变量,比如K.V.E等. 源码 public interface TypeVariable<D extends GenericDeclaration> extends Type { //获得泛型的上限,若未明确声明上边界则默认为Object Type[] getBounds(); //获取声明该类型变量实体(即获得类.方法或构造器名) D getGenericDe

  • Java源码解析之GenericDeclaration详解

    学习别人实现某个功能的设计思路,来提高自己的编程水平.话不多说,下面进入正题. GenericDeclaration 可以声明类型变量的实体的公共接口,也就是说,只有实现了该接口才能在对应的实体上声明(定义)类型变量,这些实体目前只有三个:Class(类).Construstor(构造器).Method(方法)(详见:Java源码解析之TypeVariable详解 源码 public interface GenericDeclaration { //获得声明列表上的类型变量数组 public T

  • Java源码解析之object类

    在源码的阅读过程中,可以了解别人实现某个功能的涉及思路,看看他们是怎么想,怎么做的.接下来,我们看看这篇Java源码解析之object的详细内容. Java基类Object java.lang.Object,Java所有类的父类,在你编写一个类的时候,若无指定父类(没有显式extends一个父类)编译器(一般编译器完成该步骤)会默认的添加Object为该类的父类(可以将该类反编译看其字节码,不过貌似Java7自带的反编译javap现在看不到了). 再说的详细点:假如类A,没有显式继承其他类,编译

  • Java源码解析之HashMap的put、resize方法详解

    一.HashMap 简介 HashMap 底层采用哈希表结构 数组加链表加红黑树实现,允许储存null键和null值 数组优点:通过数组下标可以快速实现对数组元素的访问,效率高 链表优点:插入或删除数据不需要移动元素,只需要修改节点引用效率高 二.源码分析 2.1 继承和实现 public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable {

  • Java源码解析之接口Collection

    一.图示 二.方法定义 我们先想一想,公司如果要我们自己去封装一些操作数组或者链表的工具类,我么需要封装哪些功能呢?不妨就是统计其 大小,增删改查.清空或者是查看否含有某条数据等等.而collection接口就是把这些通常操作提取出来,使其更全面.更通用,那现在我们就来看看其源码都有哪些方法. //返回集合的长度,如果长度大于Integer.MAX_VALUE,返回Integer.MAX_VALUE int size(); //如果集合元素总数为0,返回true boolean isEmpty(

随机推荐