并发----AQS

原创
2018/10/09 20:56
阅读数 142

1 了解AQS

要求:能够画出AQS自旋锁的图且复述出整个过程

AQS (AbstractQueuedSynchronizer)是一个帮助器,自定义锁的一个帮助器(体现在代码上 私有的内部类继承AQS)

2 了解AQS的API

要求:通过java.util.concurrent.locks 下的 Lock和 AbstractQueuedSynchronizer的api了解AQS

Acquire()

尝试获取锁,如果没有获取到锁的画,就把当前节点放置到队列的末尾

3 能够通过AQS写一个锁

自定义锁

package src.main.concurrent.AQS;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
 * 自定义锁
 * 1 实现Lock
 * 2 AQS 私有内部类继承AQS
 * 3 重写tryAcquire/tryRelease
 * compareAndSetState   通过CAS方式修改值
 * setExclusiveOwnerThread  设置当前值占有资源
 *
 * 可重入锁,在MyLock基础之上修改  获取锁 释放锁部分逻辑
 *
 * @author liuhuxiang
 * @version $Id: MyLock.java, v 0.1 2018年10月09日 21:18 liuhuxiang Exp $
 */
public class MyLock implements Lock {

    private AQSHelper aQSHelper = new AQSHelper();

    // 这里就可以体现AQS是一个帮助类
    private class AQSHelper extends AbstractQueuedSynchronizer {

        //获取锁
        //注意这里的arg表示信号量,正常来说arg为1
        @Override
        protected boolean tryAcquire(int arg) {

            //当前资源没有线程占用
            if (getState() == 0) {
                //通过CAS方式获取原子性的修改
                if (compareAndSetState(0, arg)) {
                    //设置当前值占有资源
                    setExclusiveOwnerThread(Thread.currentThread());
                    return true;
                }
             //可重入锁--获取锁修改    只要在AQS基础之上加上一个判断即可
            }else if(getExclusiveOwnerThread()==Thread.currentThread()){
                setState(getState()+arg);
                return true;
            }
            return false;
        }

        //释放锁
        @Override
        protected boolean tryRelease(int arg) {
            //减去信号量
            int state = getState() - arg;
            boolean flag = false;
            //判断释放后是否为0
            if (state == 0) {
                setExclusiveOwnerThread(null);
                setState(state);
                return true;
            }
            //存在线程安全吗?重入性的问题,当前已经独占了资源()state,所以这里不存在安全问题
            //可重入锁--释放锁修改    这里不要做任何修改,等于获取锁加了两边arg,释放锁减掉两边arg
            setState(state);
            return false;
        }

        //这里参考jdk
        public Condition newConditionObject() {
            return new ConditionObject();
        }

    }

    @Override
    public void lock() {
        aQSHelper.acquire(1);
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
        aQSHelper.acquireInterruptibly(1);
    }

    @Override
    public boolean tryLock() {
        return aQSHelper.tryAcquire(1);
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        //试图以独占模式获取对象,如果被中断则中止,如果到了给定超时时间,则会失败。

        return aQSHelper.tryAcquireNanos(1, unit.toNanos(time));
    }

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

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

使用自定义锁

package src.main.concurrent.AQS;

/**
 * 测试MyLock
 * 创建20个线程,每个线程调用++方法,验证加锁不加锁两种方式
 *
 * @author liuhuxiang
 * @version $Id: TestMyLock.java, v 0.1 2018年10月09日 21:37 liuhuxiang Exp $
 */
public class TestMyLock {

    private int m = 0;

    MyLock myLock = new MyLock();

    private int increase() {
        myLock.lock();
        try {
            return m++;
        } finally {
            //确保最终释放锁
            myLock.unlock();
        }
    }

    public static void main(String[] args) {
        TestMyLock testMyLock = new TestMyLock();
        Thread[] threads = new Thread[20];
        for (int i = 0; i < 20; i++) {
            threads[i] = new Thread(() -> {
                System.out.println(testMyLock.increase());
            });
            threads[i].start();
        }

    }

}

探讨可重入锁

package src.main.concurrent.AQS;

/**
 * 探讨重入性问题
 * 调用的时候,发现只打印了a ,为什么只打印了a,因为a()方法占用了锁,资源不为0了,所以b无法暂用资源
 *
 * 所以要去修改MyLock,多加一个可重入性的判断
 *
 * 可重入性:同一个锁多同一资源进行占有的时候,直接分配给这个线程
 *
 * @author liuhuxiang
 * @version $Id: TestMyLock2.java, v 0.1 2018年10月09日 21:46 liuhuxiang Exp $
 */
public class TestMyLock2 {

    private int m = 0;

    MyLock myLock = new MyLock();

    public void a() {
        myLock.lock();
        System.out.println("a");
        b();
        myLock.unlock();
    }

    public void b() {
        myLock.lock();
        System.out.println("b");
        myLock.unlock();

    }

    public static void main(String[] args) {
        TestMyLock2 testMyLock2 = new TestMyLock2();

        new Thread(() -> {
            testMyLock2.a();
        }).start();

    }

}
展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部