Java并发编程:锁

1. Lock

从JDK 5.0开始,Java提供了更强大的线程同步机制——通过显式定义同步锁对象来实现同步。同步锁使用 Lock 对象充当。java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对 Lock 对象加锁,线程开始访问共享资源之前应先获得 Lock 对象。ReentrantLock 类实现了 Lock ,它拥有与 synchronized 相同的并发性和内存语义,在实现线程安全的控制中,比较常用的是 ReentrantLock,可以显式加锁、释放锁。

  • java.util.concurrent.locks(Java并发锁包)
  • Lock接口的实现基本都是通过聚合了一个队列同步器AQS的子类来完成线程访问控制的。
package java.util.concurrent.locks;
import java.util.concurrent.TimeUnit;

public interface Lock {
   
	//调用该方法的当前线程将会获取锁
    void lock();
	//可中断的获取锁,即在锁的获取中可以中断当前线程
    void lockInterruptibly() throws InterruptedException;
	//尝试非阻塞的获取锁,调用该方法后立即返回,获取成功返回true,否则返回false
    boolean tryLock();
	//超时的获取锁
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
	//释放锁
    void unlock();
	//获取等待通知组件,该组件和当前锁绑定
    Condition newCondition();
}

2. AQS

  • 抽象队列同步器 AbstractQueuedSynchronizer 简称同步器,是用来构建锁或者其他同步组件的基础框架。同步器的主要使用方式是继承,子类通过继承同步器并实现他的抽象方法来管理同步状态。

抽象:抽象类,只实现一些主要逻辑,有些方法由子类实现。
队列:使用先进先出(FIFO)队列存储数据。
同步:实现了同步的功能。

  • 使用 AQS 能简单且高效地构造出应用广泛的同步器,比如 ReentrantLock、Semaphore、ReentrantReadWriteLock、SynchronousQueue、FutureTask 等都是基于 AQS 实现的。
  • 同步器依赖内部的同步队列 / 等待队列(一个FIFO双向队列)来完成同步状态的管理。当前线程获取同步状态失败时,同步器会将当前线程以及等待状态等信息构造成为一个结点(Node)并将其加入同步队列,同时会阻塞当前线程,当同步状态释放时,会把首结点中的线程唤醒,使其再次尝试获取同步状态。
  • 将获取同步状态失败的线程加入到同步队列中时,为了保证线程安全,同步器提供了一个基于CAS的设置尾结点的方法:compareAndSetTail(Node expect, Node update)
  • 同步队列中的首结点是获取同步状态成功的结点,首结点的线程在释放同步状态时,会唤醒后继结点,后继结点将会在获取同步状态成功时将自己设置为首结点。
  • 同步器的子类推荐被定义为自定义同步组件的静态内部类。
  • 同步器的设计是基于模板方法模式的,使用者需要继承同步器并重写指定的方法,随后将同步器组合在自定义同步组件的实现中,并调用同步器提供的模板方法,而这些模板方法将会调用使用者重写的方法。
  • 重写同步器指定的方法时,需要使用同步器提供的3个方法来访问或修改同步状态。
    • protected final int getState()
    • protected final void setState(int newState)
    • protected final boolean compareAndSetState(int expect, int update)
  • 同步器可重写的方法:
    • protected boolean tryAcquire(int arg)//独占式获取同步状态
    • protected boolean tryRelease(int arg)//独占式释放同步状态
    • protected int tryAcquireShared(int arg)//共享式获取同步状态
    • protected boolean tryReleaseShared(int arg)//共享式释放同步状态
    • protected boolean isHeldExclusively()//表示当前同步器是否被当前线程独占
  • 同步器提供的模板方法:
    • public final void acquire(int arg)//调用重写的tryAcquire(int arg)
    • public final void acquireInterruptibly(int arg)
    • public final boolean tryAcquireNanos(int arg, long nanosTimeout)
    • public final void acquireShared(int arg)
    • public final void acquireSharedInterruptibly(int arg)
    • public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout)
    • public final boolean release(int arg)
    • public final boolean releaseShared(int arg)
    • public final Collection<Thread> getQueuedThreads()//获取等待在同步队列上的线程集合
package java.util.concurrent.locks;

public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable {
   
    
    protected AbstractQueuedSynchronizer() {
    }

	//同步队列/等待队列中存储元素的类型为结点类
	static final class Node {
    
		//同步队列中的结点Node用来保存:
		//(1)获取同步状态失败的线程引用
		//(2)等待状态
		//(3)前驱结点
		//(4)后继结点
	}

	//Head of the wait queue, lazily initialized.
    private transient volatile Node head; //指向同步队列中的头结点
    
    //Tail of the wait queue, lazily initialized.
    private transient volatile Node tail; //指向同步队列中的尾结点

    //同步器使用一个int型的成员变量来表示同步状态
    private volatile int state;
	
	//获取当前同步状态
	protected final int getState() {
   
        return state;
    }
	
	//设置当前同步状态
	protected final void setState(int newState) {
   
        state = newState;
    }
	
	//该方法以原子操作的方式(CAS)更新state变量
	protected final boolean compareAndSetState(int expect, int update) {
   
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
    }
	
	private final boolean compareAndSetHead(Node update) {
   
        return unsafe.compareAndSwapObject(this, headOffset, null, update);
    }

    private final boolean compareAndSetTail(Node expect, Node update) {
   
        return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
    }
    
	//独占式获取同步状态、结点构造、加入同步队列、在同步队列中自旋等待
	public final void acquire(int arg) {
   
        if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
	
	//唤醒同步队列中首结点的后继结点,unparkSuccessor(Node node)通过LockSupport来唤醒处于等待状态的线程
	public final boolean release(int arg) {
   
        if (tryRelease(arg)) {
   
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }
	
	public final Collection<Thread> getQueuedThreads() {
   
        ArrayList<Thread> list = new ArrayList<Thread>();
        for (Node p = tail; p != null; p = p.prev) {
   
            Thread t = p.thread;
            if (t != null)
                list.add(t);
        }
        return list;
    }
}

3. ReentrantLock

  • ReentrantLock的实现依赖于Java同步器框架AbstractQueuedSynchronizer(AQS)。AQS使用一个int型的volatile变量state来维护同步状态。
  • ReentrantLock是可重入锁,重入是指任意线程在获取到锁之后能够再次获取该锁而不被阻塞。
    • 线程再次获取锁:锁需要去识别获取锁的线程是否为当前占有锁的线程,如果是则再次成功获取锁。
    • 锁的最终释放:获取锁时计数自增,释放锁时计数自减,计数表示当前锁被重复获取的次数,计数等于0时表示锁成功释放。

  • ReentrantLock使用公平锁时,加锁方法lock()调用轨迹如下:
    • ReentrantLock:lock()
    • FairSync:lock()
    • AbstractQueuedSynchronizer:acquire(int arg)
    • ReentrantLock:tryAcquire(int acquires) //此处真正开始加锁
  • ReentrantLock使用公平锁时,加锁方法unlock()调用轨迹如下:
    • ReentrantLock:unlock()
    • AbstractQueuedSynchronizer:release(int arg)
    • Sync:tryRelease(int releases) //此处真正开始释放锁
  • ReentrantLock使用非公平锁时,加锁方法lock()调用轨迹如下:
    • ReentrantLock:lock()
    • NonfairSync:lock()
    • AbstractQueuedSynchronizer:compareAndSetState(int expect, int update) //此处真正开始加锁
  • 公平锁和非公平锁释放锁时,最后都要写一个volatile变量state。
  • 公平锁获取锁时,首先会读volatile变量state。
  • 非公平锁获取锁时,首先会用CAS更新volatile变量state。
package java.util.concurrent.locks;

public class ReentrantLock implements Lock, java.io.Serializable {
   
	private final Sync sync;
	
	//自定义同步器,静态内部类Sync继承了队列同步器AQS
	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) {
   
                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;
        }

        protected final boolean tryRelease(int releases) {
   
            int c = getState() - releases; //每释放一次锁,同步状态值减少
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
    //当同步状态值为0时
                free = true;
                setExclusiveOwnerThread(null); //将占有锁的线程置为null
            }
            setState(c); //释放锁的最后,写volatile变量state
            return free; //返回true表示最终释放锁成功
        }
	}

	static final class FairSync extends Sync {
   
		final void lock() {
   
            acquire(1);
        }

        protected final boolean tryAcquire(int acquires) {
   
            final Thread current = Thread.currentThread();
            int c = getState(); //获取公平锁的开始,首先读volatile变量state
            if (c == 0) {
   
            	/**
            	* hasQueuedPredecessors()用于判断同步队列中当前结点是否有前驱节点,
            	* 如果该方法返回true,表示有线程比当前线程更早的请求获取锁,
            	* 因此需要等待前驱线程获取并释放锁之后才能继续获取锁。
            	*/
                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;
            }
            
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值