Java 并发程序员JAVA

【Java 并发笔记】ReentrantLock 相关整理

2018-12-21  本文已影响15人  58bc06151329

文前说明

作为码农中的一员,需要不断的学习,我工作之余将一些分析总结和学习笔记写成博客与大家一起交流,也希望采用这种方式记录自己的学习之旅。

本文仅供学习交流使用,侵权必删。
不用于商业目的,转载请注明出处。

1. ReentrantLock

public void get() {
        lock.lock();
        System.out.println(Thread.currentThread().getId());
        set();
        lock.unlock();
    }

public void set() {
        lock.lock();
        System.out.println(Thread.currentThread().getId());
        lock.unlock();
}
public ReentrantLock() {
       sync = new NonfairSync();
}

public ReentrantLock(boolean fair) {
       sync = fair ? new FairSync() : new NonfairSync();
}

1.1 公平锁与非公平锁实现

公平锁

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

非公平锁

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

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

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
}

1.2 重入锁实现

if (current == getExclusiveOwnerThread()) {
        int nextc = c + acquires;
        if (nextc < 0)
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
}

1.3 使用 ReentrantLock 场景

场景 1:如果发现该操作已经在执行中则不再执行(有状态执行)

private ReentrantLock lock = new ReentrantLock();
if (lock.tryLock()) {  //如果已经被 lock,则立即返回 false 不会等待,达到忽略操作的效果。 
         try {

            //操作

         } finally {
             lock.unlock();
         }

}

场景 2:如果发现该操作已经在执行,等待一个一个执行(同步执行,类似 synchronized)

private ReentrantLock lock = new ReentrantLock(); //参数默认false,不公平锁
// private ReentrantLock lock = new ReentrantLock(true); //公平锁
try {
    lock.lock(); //如果被其它资源锁定,会在此等待锁释放,达到暂停的效果

   //操作

} finally {
    lock.unlock();
}

场景 3:如果发现该操作已经在执行,则尝试等待一段时间,等待超时则不执行(尝试等待执行)

try {
     if (lock.tryLock(5, TimeUnit.SECONDS)) {  //如果已经被 lock,尝试等待 5s,看是否可以获得锁,如果 5s 后仍然无法获得锁则返回 false 继续执行
        try {
            //操作
        } finally {
            lock.unlock();
        }
      }
} catch (InterruptedException e) {
      e.printStackTrace(); //当前线程被中断时(interrupt),会抛 InterruptedException                 
}

场景 4:如果发现该操作已经在执行,等待执行。这时可中断正在进行的操作立刻释放锁继续下一操作。

try {
    lock.lockInterruptibly();
    //操作

} catch (InterruptedException e) {
    e.printStackTrace();
} finally {
    lock.unlock();
}

场景 5:条件判断。

Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
lock.lock();
try {
  while(条件判断表达式) {
      condition.wait();
  }
 // 处理逻辑
} finally {
    lock.unlock();
}

1.4 ReentrantLock 的方法

方法 说明
getHoldCount() 查询当前线程获取此锁的次数,此线程执行 lock 方法的次数。
getQueueLength() 返回正等待获取此锁的线程估计数,比如启动 10 个线程,1 个线程获得锁,此时返回的是 9。
getWaitQueueLength(Condition condition) 返回等待与此锁相关的给定条件的线程估计数。比如 10 个线程,用同一个 condition 对象,并且此时这 10 个线程都执行了 condition 对象的 await 方法,那么此时执行此方法返回 10。
hasWaiters(Condition condition) 查询是否有线程等待与此锁有关的给定条件(condition),对于指定 contidion 对象,有多少线程执行了 condition.await 方法。
hasQueuedThread(Thread thread) 查询给定线程是否等待获取此锁。
hasQueuedThreads() 是否有线程等待此锁。
isFair() 该锁是否公平锁。
isHeldByCurrentThread() 当前线程是否保持锁锁定,线程的执行 lock 方法的前后分别是 false 和 true。
isLock() 此锁是否有任意线程占用。
lockInterruptibly() 如果当前线程未被中断,获取锁。
tryLock() 尝试获得锁,仅在调用时锁未被线程占用,获得锁。
tryLock(long timeout, TimeUnit unit) 如果锁在给定等待时间内没有被另一个线程获取,则获取该锁。

1.5 tryLock、lock 和 lockInterruptibly 的区别

1.6 总结

上一篇 下一篇

猜你喜欢

热点阅读