Lock(三) — 自定义AQS (实践)

一、概述

上一篇分析了 Lock(二) — 队列同步器(AQS)浅析 后,这里自己实现一个AQS。

二、自定义AQS

// 自定义一个独占锁(同一时刻,只有一条线程可以访问资源)
public class CustomLock implements Lock {
	
	// 自定义同步器
    class Sync extends AbstractQueuedSynchronizer {
    
        @Override
        protected boolean isHeldExclusively() {
        	// 判断当前资源是否被独占
            return getState() == 1;
        }
        
        @Override
        protected boolean tryAcquire(int arg) {
        	// 利用CAS原子操作更新状态,更新成功表示获取到同步状态;
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        @Override
        protected boolean tryRelease(int arg) {
            if (getState() == 0) {
                throw new IllegalMonitorStateException();
            }
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }
		
		// 这个是新增的方法,AQS没有这个方法,ConditionObject内部包含一个等待队列(AQS内部维护了一个同步队列)
        final ConditionObject newCondition() {
            return new ConditionObject();
        }
    }

    private Sync sync;
    public CustomLock() {
         sync = new Sync();
    }

    @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, time);
    }

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

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

	// 这个方法是新增的,判断是否已上锁
    public Boolean isLock() {
        return sync.isHeldExclusively();
    }

    public Boolean hasQueuedThreads() {
        return sync.hasQueuedThreads();
    }
}

三、调试

public class ThreadMain {

	// 存在竞争的资源
    public static int index = 1;
	// 自定义锁
    public static CustomLock customLock = new CustomLock();

    public static void main(String[] args){
		// 此处开启20条线程去更新 index 数据,没操作一次,index自增 1,所以最后index的结果应该为20
        for (int i = 0; i < 20; i++) {
            new ThreadA("线程" + i).start();
        }

    }

    public static class ThreadA extends Thread{

        public ThreadA(String name) {
            super(name);
        }

        @Override
        public void run(){
            if (customLock.isLock()) {
                System.out.println(getName() + " -- 锁已被其他线程持有,进入等待");
            }
            // 使用锁的过程遵循before...after模式
            customLock.lock();  // before
            try{
                System.out.println(getName() + " -- index = " + index++);
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                customLock.unlock(); // after
            }
        }
    }
}

输出结果:

线程1 – index = 1
线程2 – index = 2
线程0 – index = 3
线程3 – index = 4
线程4 – index = 5
线程5 – index = 6
线程6 – index = 7
线程8 – index = 8
线程12 – index = 9
线程9 – index = 10
线程10 – 锁已被其他线程持有,进入等待
线程10 – index = 11
线程18 – index = 12
线程17 – index = 13
线程11 – 锁已被其他线程持有,进入等待
线程11 – index = 14
线程16 – index = 15
线程7 – index = 16
线程14 – 锁已被其他线程持有,进入等待
线程15 – index = 17
线程13 – index = 18
线程14 – index = 19
线程19 – 锁已被其他线程持有,进入等待
线程19 – index = 20

结论:

  1. 最终输出的 index = 20,说明线程操作 index 时是线程安全的。
  2. 线程获取锁的过程,不是公平的(线程14),存在后面的线程优先获得锁。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值