我们在并发包中用到的锁或者其他同步组件都是基于AQS构建的。
AQS 里面提供了三个基础方法:setState(),getState(),compareAndSetState();
实现者(自己扩展锁或开发一个同步组件)通过调用这几个方法就可以保证线程安全的,这也是DougLea最终的期望。
同步器既可以支持独占式获取锁,也支持获取共享锁。
锁与同步器之间的关系:锁是面向使用者的,它对用户隐藏了底层的实现细节;
同步器是面向锁的,它给锁的实现提供了基础服务。
获取当前同步状态,返回一个整形数值
设置状态,接受一个整形数值
利用CAS 线程安全的设置状态
独占式获取锁,重写时需要查询当前状态并且判断同步状态是否符合预期,然后再通过CAS设置状态值
独占式释放锁
共享式获取同步状态,返回大于等于0 表示获取成功
共享式释放同步状态
当前锁是否被当前线程独占
独占式获取同步状态如果获取锁成功,则返回,否则进入到同步队列等待,该方法会调用tryAccquire()尝试获取锁,
该方法会响应中断,
在accquireInterruptibly()基础上加了超时时间,如果在指定时间范围内没有拿到,则返回false
共享式获取同步状态,当前锁会被多个线程共享
响应中断
在accquireSharedInterruptibly()基础上添加超时时间
释放独占锁
释放共享锁
获取等待在同步队列上的集合
首先给大家一个思路,实现互斥锁的基本流程
package com.ams.thread.lesson5;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
/**
* 关注微信公众号"AI码师"获取项目源码及2021面试题一套
*
* @author: AI码师
* Date: 2021/12/30 6:09 上午
* Description:
*/
public class MyMutexLock implements Lock {
private final LockAQS lockAQS = new LockAQS();
@Override
public void lock() {
lockAQS.acquire(1);
}
@Override
public void lockInterruptibly() throws InterruptedException {
lockAQS.acquireInterruptibly(1);
}
@Override
public boolean tryLock() {
return lockAQS.tryAcquire(1);
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return lockAQS.tryAcquireNanos(1, unit.toNanos(time));
}
@Override
public void unlock() {
lockAQS.release(1);
}
@Override
public Condition newCondition() {
return lockAQS.newCondition();
}
private static class LockAQS extends AbstractQueuedSynchronizer {
@Override
protected boolean isHeldExclusively() {
return getState() == 1;
}
/**
* 重新获取锁的逻辑,只有当前同步状态为0,才允许获取成功
*
* @param arg
* @return
*/
@Override
protected boolean tryAcquire(int arg) {
// 通过cas机制去设置新值,设置成功,则代表同步状态为0
if (compareAndSetState(0, 1)) {
return true;
}
return false;
}
@Override
protected boolean tryRelease(int arg) {
// 首先判断当前state 如果当前状态值不是1 说明当前锁没有被人获取
if (getState() != 1) {
return false;
}
setExclusiveOwnerThread(null);
setState(0);
return true;
}
Condition newCondition() {
return new ConditionObject();
}
}
}
使用互斥锁
package com.ams.thread.lesson5;
import cn.hutool.core.thread.ThreadUtil;
import lombok.extern.slf4j.Slf4j;
/**
* 关注微信公众号"AI码师"获取项目源码及2021面试题一套
*
* @author: AI码师
* Date: 2021/12/30 6:08 上午
* Description:
*/
@Slf4j
public class Example16 {
private static MyMutexLock myMutexLock = new MyMutexLock();
public static void main(String[] args) {
new Thread(new Thread1()).start();
new Thread(new Thread2()).start();
}
static class Thread1 implements Runnable {
@Override
public void run() {
myMutexLock.lock();
log.info("Thread1 获取到锁");
ThreadUtil.sleep(5000);
myMutexLock.unlock();
}
}
static class Thread2 implements Runnable {
@Override
public void run() {
myMutexLock.lock();
log.info("Thread2 获取到锁");
ThreadUtil.sleep(5000);
myMutexLock.unlock();
}
}
}
关注公众号领取2022最新面试题一套和项目源码