基于AQS实现自定义锁

AQS

全称:AbstractQueuedSynchronizer,译为:抽象队列同步器。

AQS是很多并发工具类的基础,可以说是实现整个java.util.concurrent并发包的半壁江山。

public abstract class AbstractQueuedSynchronizer
    extends AbstractOwnableSynchronizer
    implements java.io.Serializable

AbstractQueuedSynchronizer是一个抽象类,本身不能实例化。

它用到了“模板方法设计模式”,定义了一个模板骨架,子类需要实现部分流程方法才能使用。

重要方法

  • int getState()
    获取同步状态。

  • void setState()
    设置同步状态。

  • boolean compareAndSetState(int expect, int update)
    基于CAS操作来设置同步状态。

setState和compareAndSetState

这两个方法的区别是:一个是非原子的,一个是原子的。

什么时候用setState?

释放锁时使用setState,因为只有获取锁的线程才能调用该方法,不存在并发问题,所以无需使用CAS操作。

什么时候用compareAndSetState?

加锁时使用compareAndSetState,因为锁竞争时是并发的,设置同步状态操作必须是CAS的,否则可能多个线程同时加锁成功。

子类重写方法

AQS的功能可以分为两类:独占式与共享式

独占式:同一时刻最多只允许一个线程获得锁,
共享式:同一时刻允许多个线程获得锁,

独占式

  • boolean tryAcquire(int arg)
    独占式尝试获取锁。

  • boolean tryRelease(int arg)
    独占式尝试释放锁。

  • boolean isHeldExclusively()
    判断当前线程是否获取独占锁。

共享式

  • boolean tryAcquireShared(int arg)
    共享式尝试获取锁。

  • boolean tryReleaseShared(int arg)
    共享式尝试释放锁。

根据自己要实现的锁类型,重写对应的方法即可。

模板方法

AQS定义了一组模板方法,子类不允许重写,可直接调用。

独占式

  • void acquire(int arg)
    独占式获取锁。

  • void acquireInterruptibly(int arg)
    独占式获取锁,支持中断。

  • boolean tryAcquireNanos(int arg,long nanos)
    独占式尝试获取锁,支持超时。

  • boolean release(int arg)
    独占式释放锁。

共享式

  • void acquireShared(int arg)
    共享式获取锁。

  • void acquireSharedInterruptibly(int arg)
    共享式获取锁,支持中断。

  • boolean tryAcquireSharedNanos(int arg,long nanos)
    共享式尝试获取锁,支持超时。

  • boolean releaseShared(int arg)
    共享式释放锁。

自定义锁实例

MyLock
/**
 * @Author: 潘
 * @Date: 2019/11/23 16:18
 * @Description: 基于Lock和AQS实现自定义锁
 */
public class MyLock implements Lock {
	//AQS实例
	private final Sync sync = new Sync();

	/**
	 * 继承AQS 实现独占锁
	 * state 0无锁  1有锁
	 */
	static class Sync extends AbstractQueuedSynchronizer{
		/**
		 * 重写tryAcquire
		 * 获取锁成功和失败均输出提示文字
		 * @param arg
		 * @return
		 */
		@Override
		protected boolean tryAcquire(int arg) {
			if (compareAndSetState(0, arg)) {
				//设置独占锁线程为当前线程
				setExclusiveOwnerThread(Thread.currentThread());
				System.out.println(Thread.currentThread().getName()+"锁竞争成功");
				return true;
			}
			System.out.println(Thread.currentThread().getName()+"锁竞争失败");
			return false;
		}

		//尝试释放锁
		@Override
		protected boolean tryRelease(int arg) {
			setState(arg);
			setExclusiveOwnerThread(null);
			return true;
		}

		@Override
		protected boolean isHeldExclusively() {
			return super.isHeldExclusively();
		}
	}

	@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 boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
		return sync.tryAcquireNanos(1, unit.toNanos(time));
	}

	@Override
	public void unlock() {
		sync.release(0);
	}

	@Override
	public Condition newCondition() {
		return sync.new ConditionObject();
	}
}

测试

class MyLockDemo{
	private MyLock lock = new MyLock();

	void test(){
		lock.lock();
		SleepUtil.sleep(1000);
		System.out.println(Thread.currentThread().getName());
		lock.unlock();
	}

	public static void main(String[] args) {
		MyLockDemo demo = new MyLockDemo();
		for (int i = 0; i < 3; i++) {
			new Thread(()->{
				demo.test();
			}).start();
		}
	}
}

输出如下:

Thread-0锁竞争成功
Thread-2锁竞争失败
Thread-1锁竞争失败
Thread-2锁竞争失败
Thread-2锁竞争失败
Thread-0
Thread-2锁竞争成功
Thread-2
Thread-1锁竞争成功
Thread-1
发布了100 篇原创文章 · 获赞 23 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/qq_32099833/article/details/103217188
今日推荐