AQS使用方式和其中的设计模式
AQS使用了模板模式,定义了线程操作需要的基本末班,继承子类只需要按照这些模板去操作
AQS常用的模板方法名
方法名称 | 描述 |
void acquire(int arg) | 独占式获取同步状态,如果当前线程获取同步状态成功,则返回; 否则就会进入同步队列等待,该方法将会调用重写的tryAcquire(int arg)方法 |
void acquireInterruptibly(int arg) | 与acquire(int arg)相同,但是该方法能够响应中断,当前线程为获取到同步状态 而进入同步队列中,如果当前线程被中断,则该方法会抛出InterruptedException并返回 |
boolean tryAcquireNanos(int arg,long nanos) | 在acquireInterruptibly(int arg)基础上增加了超时限制,如果当前线程在超时时间内没有获取到同步状态,那么就会返回发生了,如果获取到了就返回true |
void acquireShared(int arg) | 共享式地获取同步状态,如果当前线程为获取到同步状态,将会进入同步队列等待,与独占式获取的主要区别是在同一个时刻,可以有多个线程获取到同步状态 |
void acquireSharedInterruptibly(int arg) | 与acquireShared(int arg)相同,该方法响应中断 |
boolean tryAcquireSharedNanos(int arg,long nanos) | 在void acquireSharedInterruptibly(int arg)基础上加上了超时限制 |
boolean release(int arg) | 独占式地释放同步状态,该方法会在释放同步状态之后,将同步队列中第一个节点包含的线程唤醒 |
boolean releaseShared(int arg) | 共享式地释放同步状态 |
Collection<Thread> getQueuedThreads() | 获取等待在同步队列上的线程集合 |
能够被重写的方法
方法名称 | 描述 |
protected boolean tryAcquirek(int arg) | 独占式获取同步状态,实现该方法需要查询当前状态并判断同步状态是否符合预期 然后在进行CAS设置同步状态 |
protected boolean tryRelease(int arg) | 独占式释放同步状态,等待获取同步状态的贤臣干将有机会获取到同步状态 |
protected int tryAcquireShared(int arg) | 共享式获取同步状态,返回大于等于0的值,表示获取成功,防止,获取失败 |
protected boolean tryReleaseShared(int arg) | 共享式释放同步状态 |
protected boolean isHeldExclusively() | 当前同步器是否在独占模式先被贤臣高占勇,一般发方法表示是否被当前线程锁独占 |
访问或者修改同步状态是,需要通过修改state的值来改变同步状态
getState() | 获取当前同步状态 |
setState(int newState) | 设置当前同步状态 |
compareAndSetState(int expect,int update) | 使用CAS设置当前状态,该方法能够保证状态设置的原子性 |
代码示例,实现自己的独占锁:通过参考ReentrentLock
1、实现loc接口
2、内部内继承AQS
注:自己手动写过之后,发现独占锁写起来还是比较简单的,实现所有lock的方法,内部类Syn编写释放和获取锁的方法,由于是独占锁,所以不用关心共享Share相关的方法,代码如下
public class MyLock implements Lock {
class Syn extends AbstractQueuedSynchronizer{
//尝试获取锁
@Override
protected boolean tryAcquire(int arg) {
if(compareAndSetState(0,1)){
//设置当前拥有独占访问的线程
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
@Override
protected boolean tryRelease(int arg) {
if(getState() == 0){
throw new IllegalMonitorStateException();
}else{
setExclusiveOwnerThread(null);
setState(0);
return true;
}
}
//因为是独占锁,所以shared方法就不用管了
Condition newCondition(){return new ConditionObject();}
}
//新建一个操作的代理Syn
Syn syn = new Syn();
@Override
public void lock() {
System.out.println(Thread.currentThread().getName()+":开始获取锁");
syn.acquire(1);
System.out.println(Thread.currentThread().getName()+":已经获取锁");
}
@Override
public void lockInterruptibly() throws InterruptedException {
syn.acquireInterruptibly(1);
}
@Override
public boolean tryLock() {
return syn.tryAcquire(1);
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return syn.tryAcquireNanos(1,unit.toNanos(time));
}
@Override
public void unlock() {
System.out.println(Thread.currentThread().getName()+":准备释放锁");
syn.release(1);
System.out.println(Thread.currentThread().getName()+":释放锁完成");
}
@Override
public Condition newCondition() {
return syn.newCondition();
}
}
使用自定义独占锁:使用方法和ReentrantLock相同,
public class Test {
private static Lock lock = new MyLock();
static class Customer extends Thread {
@Override
public void run() {
lock.lock();
try {
System.out.println(Thread.currentThread().getName()+":开始执行任务,任务时间1秒");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public static void main(String[] args) {
for (int i = 0; i < 4; i++) {
new Customer().start();
}
}
}
结果:启动四个线程,在每一个线程执行完之后,才能执行下一个线程
Thread-0:开始获取锁
Thread-2:开始获取锁
Thread-1:开始获取锁
Thread-0:已经获取锁
Thread-3:开始获取锁
Thread-0:开始执行任务,任务时间1秒
Thread-0:准备释放锁
Thread-0:释放锁完成
Thread-2:已经获取锁
Thread-2:开始执行任务,任务时间1秒
Thread-2:准备释放锁
Thread-2:释放锁完成
Thread-1:已经获取锁
Thread-1:开始执行任务,任务时间1秒
Thread-1:准备释放锁
Thread-1:释放锁完成
Thread-3:已经获取锁
Thread-3:开始执行任务,任务时间1秒
Thread-3:准备释放锁
Thread-3:释放锁完成