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

介绍

本文将介绍如何应用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
    

    猜你喜欢

    转载自blog.csdn.net/qq_25956141/article/details/89525192
    今日推荐