并发----AQS

1 了解AQS

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

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

c41dc293b3707ab9587a621053c0d535f84.jpg

2 了解AQS的API

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

ab19e00372e2b36602d82c5fd8948150947.jpg

Acquire()

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

adb59cc7eb4c4f6df87688b73171f56c10b.jpg

7ca98d2d3a5861e334d9b2f989785ff35bd.jpg

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();

    }

}

转载于:https://my.oschina.net/u/3523594/blog/2236923

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值