重入锁synchroized,reentrantlock

重入锁:在同一个线程内可以对同一个资源锁多次,且都可以上锁成功。

能够重入的锁有synchroized和reentrantLock

一、synchroized

public class AddNum {

    private Integer num = 9;
    public int add(int a){
        synchronized (num){
            num = num+a;
        }
        return num;
    }

    public int sub(int b){
        synchronized (num){
            num = num - b;
        }
        return num;
    }
    public static void main(String[] args) {
        AddNum addNum = new AddNum();
        System.out.println(addNum.add(1)+addNum.sub(2));
    }
}
javap -c AddNum.class 
Compiled from "AddNum.java"
public class com.kaiyuan.p2p.uploadxw.application.AddNum {
  public com.kaiyuan.p2p.uploadxw.application.AddNum();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: aload_0
       5: bipush        9
       7: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      10: putfield      #3                  // Field num:Ljava/lang/Integer;
      13: return

  public int add(int);
    Code:
       0: aload_0
       1: getfield      #3                  // Field num:Ljava/lang/Integer;
       4: dup
       5: astore_2
       6: monitorenter
       7: aload_0
       8: aload_0
       9: getfield      #3                  // Field num:Ljava/lang/Integer;
      12: invokevirtual #4                  // Method java/lang/Integer.intValue:()I
      15: iload_1
      16: iadd
      17: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      20: putfield      #3                  // Field num:Ljava/lang/Integer;
      23: aload_2
      24: monitorexit
      25: goto          33
      28: astore_3
      29: aload_2
      30: monitorexit
      31: aload_3
      32: athrow
      33: aload_0
      34: getfield      #3                  // Field num:Ljava/lang/Integer;
      37: invokevirtual #4                  // Method java/lang/Integer.intValue:()I
      40: ireturn
    Exception table:
       from    to  target type
           7    25    28   any
          28    31    28   any

  public int sub(int);
    Code:
       0: aload_0
       1: getfield      #3                  // Field num:Ljava/lang/Integer;
       4: dup
       5: astore_2
       6: monitorenter
       7: aload_0
       8: aload_0
       9: getfield      #3                  // Field num:Ljava/lang/Integer;
      12: invokevirtual #4                  // Method java/lang/Integer.intValue:()I
      15: iload_1
      16: isub
      17: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      20: putfield      #3                  // Field num:Ljava/lang/Integer;
      23: aload_2
      24: monitorexit
      25: goto          33
      28: astore_3
      29: aload_2
      30: monitorexit
      31: aload_3
      32: athrow
      33: aload_0
      34: getfield      #3                  // Field num:Ljava/lang/Integer;
      37: invokevirtual #4                  // Method java/lang/Integer.intValue:()I
      40: ireturn
    Exception table:
       from    to  target type
           7    25    28   any
          28    31    28   any

  public static void main(java.lang.String[]);
    Code:
       0: new           #5                  // class com/kaiyuan/p2p/uploadxw/application/AddNum
       3: dup
       4: invokespecial #6                  // Method "<init>":()V
       7: astore_1
       8: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;
      11: aload_1
      12: iconst_1
      13: invokevirtual #8                  // Method add:(I)I
      16: aload_1
      17: iconst_2
      18: invokevirtual #9                  // Method sub:(I)I
      21: iadd
      22: invokevirtual #10                 // Method java/io/PrintStream.println:(I)V
      25: return
}

每一个monitorenter和monitorexit为一个锁的加锁到释放锁的过程,若能获取资源则加一,释放资源后则减一。执行多个monitorexit是为了保证锁能够被释放。

 

二、ReentrankLock

直接上代码

 ReentrantLock lock = new ReentrantLock();
        lock.lock();

底层为:ReenTrantLock

/**

*获取锁。

**<p>如果锁不是由另一个线程持有,则获取该锁并返回立即,将锁定保持计数设置为1。

**<p>如果当前线程已经持有锁,则count递增1,方法立即返回。

**<p>如果锁由另一个线程持有,则当前线程在线程调度中被禁用目的和休眠直到锁被获得,此时锁定保持计数设置为1。

*/

**
     * 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();
    }

看下底层代码实现

接口为

/**
 * Performs {@link Lock#lock}. The main reason for subclassing
 * is to allow fast path for nonfair version.
 */
abstract void 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);
        }
/**
     * 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);
    }

 /**
     * Sets the thread that currently owns exclusive access.
     * A {@code null} argument indicates that no thread owns access.
     * This method does not otherwise impose any synchronization or
     * {@code volatile} field accesses.
     * @param thread the owner thread
     */
    protected final void setExclusiveOwnerThread(Thread thread) {
        exclusiveOwnerThread = thread;
    }

/**
     * 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) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
compareAndSetState方法中,翻译为原子地将同步状态设置为给定的已更新值(如果当前状态值等于预期值)。如果原来在当前线程中状态可以由0变成1,则将锁标记为当前的线程。否则执行acquire(int arg)方法。

acquire(int arg)的tryAcquire(arg)实现

/**
     * Attempts to acquire in exclusive mode. This method should query
     * if the state of the object permits it to be acquired in the
     * exclusive mode, and if so to acquire it.
     *
     * <p>This method is always invoked by the thread performing
     * acquire.  If this method reports failure, the acquire method
     * may queue the thread, if it is not already queued, until it is
     * signalled by a release from some other thread. This can be used
     * to implement method {@link Lock#tryLock()}.
     *
     * <p>The default
     * implementation throws {@link UnsupportedOperationException}.
     *
     * @param arg the acquire argument. This value is always the one
     *        passed to an acquire method, or is the value saved on entry
     *        to a condition wait.  The value is otherwise uninterpreted
     *        and can represent anything you like.
     * @return {@code true} if successful. Upon success, this object has
     *         been acquired.
     * @throws IllegalMonitorStateException if acquiring would place this
     *         synchronizer in an illegal state. This exception must be
     *         thrown in a consistent fashion for synchronization to work
     *         correctly.
     * @throws UnsupportedOperationException if exclusive mode is not supported
     */
    protected boolean tryAcquire(int arg) {
        throw new UnsupportedOperationException();
    }

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) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            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;
        }
/**
     * Acquires in exclusive uninterruptible mode for thread already in
     * queue. Used by condition wait methods as well as acquire.
     *
     * @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);
        }
    }

/**
     * Creates and enqueues node for current thread and given mode.
     *
     * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
     * @return the new node
     */
    private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode);
        // Try the fast path of enq; backup to full enq on failure
        Node pred = tail;
        if (pred != null) {
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        enq(node);
        return node;
    }

/**
     * Inserts node into queue, initializing if necessary. See picture above.
     * @param node the node to insert
     * @return node's predecessor
     */
    private Node enq(final Node node) {
        for (;;) {
            Node t = tail;
            if (t == null) { // Must initialize
                if (compareAndSetHead(new Node()))
                    tail = head;
            } else {
                node.prev = t;
                if (compareAndSetTail(t, node)) {
                    t.next = node;
                    return t;
                }
            }
        }
    }

tryAcquire(arg)抽象类中的接口有两种实现,但是最终都是执行到nonfairTryAcquire(int acquires)方法中,如果当前没有锁,先设置当前线程的锁,如果存在锁,则给status进行+1;

addWriter(Node node),如果当前锁存在尾巴节点,则在尾巴节点后保存当前线程节点,否则保存当前节点,并返回当前节点。

/*
     * Various flavors of acquire, varying in exclusive/shared and
     * control modes.  Each is mostly the same, but annoyingly
     * different.  Only a little bit of factoring is possible due to
     * interactions of exception mechanics (including ensuring that we
     * cancel if tryAcquire throws exception) and other control, at
     * least not without hurting performance too much.
     */

    /**
     * Acquires in exclusive uninterruptible mode for thread already in
     * queue. Used by condition wait methods as well as acquire.
     *
     * @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);
        }
    }

如果node的前节点是head,因为head初始化时,都是假节点,不代表有线程拥有锁,所以,再次尝试获取锁,如果获取锁,则将锁的 head 设置为当前获取锁的线程的 Node,然后返回 false。返回 false, 则代表 if (!tryAcquire(arg) &&  acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) 的结果为 false,直接返回,并不需要设置中断标记。如果当前节点不是head的话,则说明该锁被别的线程占用了,那就需要等待其他线程释放该锁
 

意味着,对于同一个线程,可以对同一个资源加无限制次锁,但是加多少次锁就需要解多少次锁。相比之下,synchroized方法是不需要手动解锁的,可以自动解锁。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值