Java8 Lock锁详解(AQS,CAS)

您所在的位置:网站首页 lock的过去式是什么怎么写 Java8 Lock锁详解(AQS,CAS)

Java8 Lock锁详解(AQS,CAS)

2024-03-22 03:59| 来源: 网络整理| 查看: 265

什么是Lock锁?

Lock锁提供了的比synchronized关键字更加灵活的锁操作,是代码层面的锁操作。 在这里插入图片描述

为什么要使用Lock锁?

Lock锁和synchronized关键字的对比

类型synchronized关键字Lock锁获取锁无超时时间,未获取到则阻塞等待(占用cpu资源),且无法被中断非阻塞,可以被中断,未获取到则排队,中断,可以自定义超时时间共享锁不支持读写锁ReadWriteLock支持释放锁必须在当前代码块中,因为synchronized是以{}来锁住共享资源的可以在任意位置释放锁(其他方法或者其他类)

概念普及 公平锁:保证每个线程都能获取到锁(排队先进来的先获取到锁),能够避免线程饥饿 非公平锁:谁抢到就是谁的,抢不到就排队 悲观锁:每次更新和读取都加锁,对于读多写少这种场景不利,适用于于写多读少的场景 乐观锁:更新失败则重试,适用一个标记位来控制,适用于多读的场景。 可重入锁:同一线程多次进入无需重新获取锁 共享锁(读锁):一个锁可以同时被多个线程拥有,ReentrantReadWriteLock的读锁为共享锁,写锁为排他锁 排他锁(写锁):独占锁,一个锁在某一时刻只能被一个线程占有,其它线程必须等待锁被释放之后才可能获取到锁,ReentrantLock就是排他锁。

如何使用? public class LockTest { // 这个必须放在成员变量或者作为方法参数进行传递。具体原因见后面代码分析 private final Lock lock = new ReentrantLock(); // 共享资源a private int a = 0; public static void main(String[] args) throws InterruptedException { LockTest lockTest = new LockTest(); for (int i = 0; i for (int j = 0; j try { // 这块加锁也应该放到for循环外面。放里面会有性能问题。每+1就释放锁, // 正常用该是+n然后等待cpu调度,然后释放锁 lock.lock(); ++a; } finally { lock.unlock(); } } } 类功能分析

在这里插入图片描述 lock所有相关的代码都在java.utils.concurrent.locks这个包下。其中Lock和ReadWriteLock接口类是对外暴露的api 涉及到的设计模式:模板设计模式,组合模式 AbstractOwnableSynchronizer:AbstractQueuedSynchronizer的父类,仅仅是为了让子类能够设置和获取独占线程。

public abstract class AbstractOwnableSynchronizer { protected AbstractOwnableSynchronizer() { } private transient Thread exclusiveOwnerThread; protected final void setExclusiveOwnerThread(Thread thread) { exclusiveOwnerThread = thread; } protected final Thread getExclusiveOwnerThread() { return exclusiveOwnerThread; } }

AbstractQueuedSynchronizer:提供了对Lock接口中,lock,tryLock(),unlock(),等方法的通用实现和通用方法(模板设计模式),相当于是一个工具类。 对于每一种锁,lock,tryLock,unlock又有其不同的实现。所以对于每一种Lock锁的实现,都会定义一个Sync的内部类。来实现其特有功能。 在这里插入图片描述 例如ReentrantLock类的实现如下。ReentrantLock的lock,tryLock等方法都是调用其内部类Sync的方法。

public class ReentrantLock implements Lock { private final Sync sync; abstract static class Sync extends AbstractQueuedSynchronizer { // 由两个子类(FairSync和NonfairSync)来实现。 // 非公平锁直接使用cas抢(设置锁标志位为1),抢不到就按照正常的流程来(排队,先进先出(先等待的先获取到锁)) // 公平锁走正常流程(排队,先进先出) abstract void lock(); final boolean nonfairTryAcquire(int acquires) { // ... } protected final boolean tryRelease(int releases) { // ... } protected final boolean isHeldExclusively() { // ... } } public void lock() { // 调用内部类Sync的实现 sync.lock(); } public void lockInterruptibly() throws InterruptedException { // 调用内部类Sync的实现 sync.acquireInterruptibly(1); } public boolean tryLock() { // 调用内部类Sync的实现 return sync.nonfairTryAcquire(1); } public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { // 调用内部类Sync的实现 return sync.tryAcquireNanos(1, unit.toNanos(timeout)); } public void unlock() { // 调用内部类Sync的实现 sync.release(1); } }

从上面的实现可以看出,如果Sync类是public的。我们其实可以直接使用Sync类来进行并发编程。使用Lock接口来包装一层只是让我们使用更加方便而已。

LockSupport类:工具类,方法都是public static的。用于挂起,恢复一个线程。

public class LockSupport { private LockSupport() {} // Cannot be instantiated. private static void setBlocker(Thread t, Object arg) { // Even though volatile, hotspot doesn't need a write barrier here. UNSAFE.putObject(t, parkBlockerOffset, arg); } // 恢复线程 public static void unpark(Thread thread) { if (thread != null) UNSAFE.unpark(thread); } // 挂起线程 public static void park(Object blocker) { Thread t = Thread.currentThread(); setBlocker(t, blocker); UNSAFE.park(false, 0L); setBlocker(t, null); } public static void parkNanos(Object blocker, long nanos) { if (nanos > 0) { Thread t = Thread.currentThread(); setBlocker(t, blocker); UNSAFE.park(false, nanos); setBlocker(t, null); } } public static void parkUntil(Object blocker, long deadline) { Thread t = Thread.currentThread(); setBlocker(t, blocker); UNSAFE.park(true, deadline); setBlocker(t, null); } public static Object getBlocker(Thread t) { if (t == null) throw new NullPointerException(); return UNSAFE.getObjectVolatile(t, parkBlockerOffset); } ReentrantLock源码剖析

private final Lock lock = new ReentrantLock();

lock加锁 // 默认为非公平锁 public ReentrantLock() { // NonfairSync是Sync的一个实现类,实现了他的lock方法 sync = new NonfairSync(); }

ReentrantLock#lock方法调用的是其内部类Sync的lock方法

public void lock() { // 由于默认为非公平锁,所有这里调用的是NonfairSync的lock方法 sync.lock(); }

NonfairSync类

static final class NonfairSync extends Sync { final void lock() { // 使用cas加锁(如果state等于0则设置为1返回true,否则返回false), // 只有没有任何线程持有锁时,这里才会返回true if (compareAndSetState(0, 1)) // 加锁成功则设置独占线程为当前线程 setExclusiveOwnerThread(Thread.currentThread()); else // 加锁失败则调用AbstractQueuedSynchronizer类的acquire方法 acquire(1); } protected final boolean tryAcquire(int acquires) { // 调用父类Sync的nonfairTryAcquire方法 return nonfairTryAcquire(acquires); } } // AbstractQueuedSynchronizer类的acquire方法 public final void acquire(int arg) { // 调用NonfairSync类的tryAcquire方法 if (!tryAcquire(arg) && // 如果tryAcquire返回false,加锁失败则进行排队 acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) // 两个都是false。则当前线程请求锁失败,中断自己。 selfInterrupt(); } // Sync类 abstract static class Sync extends AbstractQueuedSynchronizer { abstract void lock(); final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); // 获取当前锁状态 int c = getState(); if (c == 0) { // 为0则表示锁是空闲状态,则加锁 if (compareAndSetState(0, acquires)) { // 设置独占线程为自己 setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { // 如果自己就是独占线程,则只是将锁的状态标志位+1 // acquires外部传的是1,一般也不会出现其他数字 // 这里就是锁的可重入实现。只是增加状态值,释放锁时再减状态值。 int nextc = c + acquires; if (nextc // 调用Sync类的tryRelease方法 if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) // 如果有线程在等待锁释放,则将该线程恢复 unparkSuccessor(h); // 没有线程在等待资源,则直接返回true return true; } return false; } // 返回当前锁的状态(true空闲,false,表示当前线程多次获取锁,是重入状态) protected final boolean tryRelease(int releases) { // 锁的状态标志位-1 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; }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3