一、概述
上一篇分析了 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
结论:
- 最终输出的 index = 20,说明线程操作 index 时是线程安全的。
- 线程获取锁的过程,不是公平的(线程14),存在后面的线程优先获得锁。