自定义实现一个锁
大约 2 分钟
- Lock
- AQS
- new AQS
最简易的实现(不可重入锁)
设计模式:
模版模式(AQS其实就是一个动态模版,类似Tread类,重写其中的部分方法+重用方法就可以实现同步器的功能)
组合模式(Lock接口面向使用者,AQS抽象类面向开发者,实现类实现了Lock接口并在内部有一个成员类继承了AQS)
依赖倒置(类结构分为三层,Lock接口面向使用者,AQS定义开发者需要实现的功能,实现类完成具体实现)
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
public class MyLock implements Lock {
class MySync extends AbstractQueuedSynchronizer {
protected MySync() {
super();
}
@Override
protected boolean tryAcquire(int arg) {
if(compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
@Override
protected boolean tryRelease(int arg) {
if(getExclusiveOwnerThread()!=Thread.currentThread()){
throw new IllegalMonitorStateException();
}
setExclusiveOwnerThread(null);
//这里必须保证不会发生指令重排,否则可能发生另一个线程竞争到了锁,然后当前线程把ExclusiveOwnerThread改成了null
//state被volatile修饰,放在后面执行可以加读写屏障,保证有序性
setState(0);
return true;
}
@Override//是否持有独占锁
protected boolean isHeldExclusively() {
if(getExclusiveOwnerThread()==Thread.currentThread()){
return getState() == 1;
}else {
throw new IllegalMonitorStateException();
}
}
protected Condition newCondition() {
return new ConditionObject();
}
}
MySync sync = new MySync();
//获取锁,失败进入阻塞队列
@Override
public void lock() {
sync.acquire(1);
}
//获取锁,获取锁过程中可以被打断,失败进入阻塞队列
@Override
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
//尝试获取锁,失败直接返回
@Override
public boolean tryLock() {
return sync.tryAcquire(1);
}
//尝试获取锁time时间
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(time));
}
//释放锁(失败?)
@Override
public void unlock() {
sync.release(1);
}
//新建一个等待队列
@Override
public Condition newCondition() {
return sync.newCondition();
}
}
class Test{
public static void main(String[] args) throws InterruptedException {
MyLock lock = new MyLock();
new Thread(()->{
lock.lock();
try {
System.out.println(Thread.currentThread().getName());
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}finally {
lock.unlock();
}
},"1").start();
new Thread(()->{
lock.lock();
try {
System.out.println(Thread.currentThread().getName());
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}finally {
lock.unlock();
}
},"2").start();
}
}