本文将介绍如何应用AbstractQueuedSynchronizer实现一个简单的Lock锁。至于AbstractQueuedSynchronizer的原理在博主其他文章中有介绍,本文重点讲述其应用。AbstractQueuedSynchronizer使用一个队列维护所有的等待锁释放的线程,队列中的每个结点通过自旋的方式来争抢锁,当同步结点释放锁,唤醒next结点。在自旋中,该线程序判断当前结点的前驱是否为队头结点,以及是否能够通过tryAcquire(int)设置同步状态,若是则将其设置成队头结点。
通过上述的介绍可知,锁的获取顺序和队列中结点的顺序一致,因此保证了公平锁的锁获取顺序顺序。在公平锁中,通过tryAcquire(int)获取同步状态方法中,设置同步状态之前,先通过判断是否有在排队的结点,若有,则先处理前面的,并将其加入到同步队列中。但在非公平锁中,会先直接尝试获取锁,即不会判断队列中是否还有没有排队的线程就直接尝试获取锁,获取不到才将其加入到同步队列中。
AbstractQueuedSynchronizer是一个抽象类,其定义了一套模版,需实现者重写其tryAcquire(int)、tryRelease(int)、isHeldExclusively()等方法。
在同步器中,会调用上述方法来实现同步器。开发者需维护一个同步状态即可完成Lock的定制。
同步器主要提供的API如下:
本文通过重写抽象同步器的抽象方法来实现一个锁。
import urrent.TimeUnit;
import urrent.locks.AbstractQueuedSynchronizer;
import urrent.locks.Condition;
import urrent.locks.Lock;public class Mutex implements Lock{//创造一个同步器//该同步器用一个state来维护,当state表示同一时间当前同步状态的线程数量private static class Sync extends AbstractQueuedSynchronizer{@Overrideprotected boolean tryAcquire(int arg) {if(compareAndSetState(0, arg)){ //CAS操作的原子性,若当前线程设置成1,其他线程无法设置成功setExclusiveOwnerThread(Thread.currentThread());return true;}return false;}@Overrideprotected boolean tryRelease(int arg) {if(getState() == 0)throw new IllegalMonitorStateException();setExclusiveOwnerThread(null);setState(0); //由于获取到了锁,因此这一步无需通过CAS操作保证原子性return true;}//是否处于占用状态@Overrideprotected boolean isHeldExclusively() {return getState() == 1;}//返回一个ConditionCondition newCondition(){return new ConditionObject();}}private final Sync sync = new Sync(); //final域能保证在初始化之前只对一个线程可见@Overridepublic void lock() {sync.acquire(1);}@Overridepublic void lockInterruptibly() throws InterruptedException {sync.acquireInterruptibly(1);}@Overridepublic boolean tryLock() {Acquire(1);}@Overridepublic void unlock() {lease(1);}@Overridepublic Condition newCondition() {wCondition();}public boolean isLocked(){return sync.isHeldExclusively();}//判断当前同步队列中是否还有等待获取锁public boolean hasQueuedThreads(){return sync.hasQueuedThreads();}public boolean tryLock(long timeout,TimeUnit unit) throws InterruptedException{AcquireNanos(1, Nanos(timeout));}
}
使用自定义锁:
import urrent.locks.Lock;public class Test {public static void main(String[] args) {final Lock lock = new Mutex();Thread t1 = new Thread(new Runnable() {@Overridepublic 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() {@Overridepublic 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
本文发布于:2024-02-02 20:20:04,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170687640346207.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |