一个简单排他锁的原理与实现

阅读: 评论:0

一个简单排他锁的原理与实现

一个简单排他锁的原理与实现

介绍

本文将介绍如何应用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 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 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23