介绍
本文将介绍如何应用AbstractQueuedSynchronizer实现一个简单的Lock锁。至于AbstractQueuedSynchronizer的原理在博主其他文章中有介绍,本文重点讲述其应用。AbstractQueuedSynchronizer使用一个队列维护所有的等待锁释放的线程,队列中的每个结点通过自旋的方式来争抢锁,当同步结点释放锁,唤醒next结点。在自旋中,该线程序判断当前结点的前驱是否为队头结点,以及是否能够通过tryAcquire(int)设置同步状态,若是则将其设置成队头结点。
通过上述的介绍可知,锁的获取顺序和队列中结点的顺序一致,因此保证了公平锁的锁获取顺序顺序。在公平锁中,通过tryAcquire(int)获取同步状态方法中,设置同步状态之前,先通过判断是否有在排队的结点,若有,则先处理前面的,并将其加入到同步队列中。但在非公平锁中,会先直接尝试获取锁,即不会判断队列中是否还有没有排队的线程就直接尝试获取锁,获取不到才将其加入到同步队列中。
AbstractQueuedSynchronizer API
AbstractQueuedSynchronizer是一个抽象类,其定义了一套模版,需实现者重写其tryAcquire(int)、tryRelease(int)、isHeldExclusively()等方法。
- tryAcquire(int),尝试获取同步状态
- tryRelease(int),尝试释放同步状态
- tryAcquireShared(int),尝试获取共享同步状态
- tryReleaseShared(int),尝试释放共享同步状态
- isHeldExclusively(),当前同步器是否被当前线程所占
在同步器中,会调用上述方法来实现同步器。开发者需维护一个同步状态即可完成Lock的定制。
同步器主要提供的API如下:
- void acquire(int),会调用开发者的tryAcquire(int)方法设置同步状态,若设置失败将其加入到同步队列中。
- boolean tryAcqureNanos(int,long),第一个参数为同步状态,第二个参数为纳秒时间,带有时间的尝试获取锁。
- void acquireShared(int),获取共享同步状态
- void release(int),释放同步状态
- void releaseShared(int),释放共享同步状态。
一个简单的Lock锁实现
本文通过重写抽象同步器的抽象方法来实现一个锁。
import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.AbstractQueuedSynchronizer; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; public class Mutex implements Lock{ //创造一个同步器 //该同步器用一个state来维护,当state表示同一时间当前同步状态的线程数量 private static class Sync extends AbstractQueuedSynchronizer{ @Override protected boolean tryAcquire(int arg) { if(compareAndSetState(0, arg)){ //CAS操作的原子性,若当前线程设置成1,其他线程无法设置成功 setExclusiveOwnerThread(Thread.currentThread()); return true; } return false; } @Override protected boolean tryRelease(int arg) { if(getState() == 0)throw new IllegalMonitorStateException(); setExclusiveOwnerThread(null); setState(0); //由于获取到了锁,因此这一步无需通过CAS操作保证原子性 return true; } //是否处于占用状态 @Override protected boolean isHeldExclusively() { return getState() == 1; } //返回一个Condition Condition newCondition(){ return new ConditionObject(); } } private final Sync sync = new Sync(); //final域能保证在初始化之前只对一个线程可见 @Override public void lock() { sync.acquire(1); } @Override public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); } @Override public boolean tryLock() { return sync.tryAcquire(1); } @Override public void unlock() { sync.release(1); } @Override public Condition newCondition() { return sync.newCondition(); } public boolean isLocked(){ return sync.isHeldExclusively(); } //判断当前同步队列中是否还有等待获取锁 public boolean hasQueuedThreads(){ return sync.hasQueuedThreads(); } public boolean tryLock(long timeout,TimeUnit unit) throws InterruptedException{ return sync.tryAcquireNanos(1, unit.toNanos(timeout)); } }
使用自定义锁:
import java.util.concurrent.locks.Lock; public class Test { public static void main(String[] args) { final Lock lock = new Mutex(); Thread t1 = new Thread(new Runnable() { @Override public void run() { lock.lock(); try{ for (int i = 0; i < 10; i++) { try { System.out.println(Thread.currentThread().getName() + "-"+ i); Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } }finally{ lock.unlock(); } } },"Thread1"); Thread t2 = new Thread(new Runnable() { @Override public void run() { lock.lock(); try{ for (int i = 0; i < 10; i++) { try { System.out.println(Thread.currentThread().getName() + "-" + i); Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } }finally{ lock.unlock(); } } },"Thread2"); t1.start(); t2.start(); } }
输出结果:
Thread1-0 Thread1-1 Thread1-2 Thread1-3 Thread1-4 Thread1-5 Thread1-6 Thread1-7 Thread1-8 Thread1-9 Thread2-0 Thread2-1 Thread2-2 Thread2-3 Thread2-4 Thread2-5 Thread2-6 Thread2-7 Thread2-8 Thread2-9