1、lock
Lock 接口是Java并发包中最基础的一个接口,相应的它定义了一些锁的基本功能。相比synchronized关键字,具有以下特征:
可以尝试非阻塞地获取锁
可中断的获取锁
定时获取锁
Lock这个基础接口的相对比较简单,有如下方法:
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock();
2 、同步器
队列同步器 AbstractQueuedSynchronizer ,使用来构建锁或者其他同步组件的基础框架,它使用一个int成员变量表示同步状态。通过内置FIFO队列来完成资源获取线程的排队工作。
同步器提供了三个方法来进行对状态值的操作。
getState
setState(int newState)
compareAndSetState(int expect ,int update)
同步器可以支持独占式地获取同步状态,也可以共享式地获取同步状态。
同步其是实现锁(任意同步组件)的关键,在锁的实现中聚合同步器,利用同步其实现锁的语义。
锁是面试使用者的,它定义了使用者与锁交互的接口,隐藏了实现细节。
同步器面向的是锁的实现者,它简化了锁的实现方式,屏蔽了同步状态管理,线程的排队,等待与唤醒等底层操作。
3、 同步器的内部实现:
3.1同步器的设计原理:
同步器的设计是基于模板方法模式的,也就是说,使用者需要继承同步器并重写指定的方法,随后将同步器组合在定义同步组件的实现中,并调用同步器提供的模板方法,而这些模板方法将会调用使用者重写的方法。
3.2 同步器可重写的方法:
//独占式获取锁和释放锁的方法:
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
实现该方法,需要查询当前状态并判断同步状态是否符合预期,然后再 进行CAS设置同步状态。
//独占式释放同步状态,等待获取同步状态线程将有机会获取同步状态。
protected boolean tryRelease(int arg) {
throw new UnsupportedOperationException();
}
共享式获取锁和释放锁的方法:
//共享式获取同步状态,返回大于等于0的值,表示获取成功,反之获取失败。
protected int tryAcquireShared(int arg) {
throw new UnsupportedOperationException();
}
//共享式释放同步状态。
protected boolean tryReleaseShared(int arg) {
throw new UnsupportedOperationException();
}
//当前同步器是否在独占模式下被线程占用,一般该方法表示是否被当前线程所独占。
protected boolean isHeldExclusively() {
throw new UnsupportedOperationException();
}
3.3同步器提供的模板方法
void acquire(int arg)
独占式获取同步状态,如果当前线程获取同步状态成功,则由该方法返回,否则,将会进入同步队列等待,该方法将会调用重写的tryAcquire(int arg)方法。
void acquireInterruptibly(int arg)
与 acquire 方法相同,但是该方法相应中断,当前线程未获取到同步状态而进入同步队列中,如果当前线程被中断,则该方法抛出InterruptedException并返回。
boolean tryAcquireNanos(int arg, long nanos)
在 基础上增加了超时限制,如果当前线程在超时时间内没有获取到同步状态,那么将会返回false,如果获取到了返回true。
boolean acquireShared(int arg)
共享式的获取同步状态,如果当前线程为获取到同步状态,将会进入同步对列等待,与独占式获取的主要区别是在同一时刻可以有多个线程获取到同步状态。
void acquireSharedInterruptibly(int arg)
该方法响应中断。
void tryAcquireSharedNanos(int arg,long nanos)
在基础上了增加了超时限制。
boolean release(int arg)
独占式的释放同步状态,该方法会在释放同步状态之后,将同步队列中第一节点包含的线程唤醒。
boolean releaseShared(int arg)
共享式的释放同步状态,
boolean releaseShared(int arg)
获取等待在同步对列上的线程集合。
4、 独占锁的示例
独占锁就是在同一时刻只能又一个线程获取到锁,而其他获取锁的线程只能处于同步队列中等待,只有获取锁的线程释放了锁,后继的线程才能够获取锁。
上面说了,同步器采用了模板的设计模式,需要重写相应的方法,独占锁自然只要重写独占式的方法就可以了:
public class Mutex implements Lock{
private static class Sync extends AbstractQueuedSynchronizer{
protected boolean isHeldExclusively(){
return getState()==1;
}
public boolean tryAcquire(int acuqires){
if(compareAndSetState(0,1)){
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
protected boolean tryRelease(int releases){
if(getState()==0) throw new IllegalMonitorStateException();
setExclusiveOwnerThread(null);
setState(0);
return true;
}
Condition newCondition(){
return new ConditionObject();
}
}
private final Sync sync = new Sync();
public void lock() {
sync.acquire(1);
}
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
public boolean tryLock() {
return sync.tryAcquire(1);
}
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireNanos(1,unit.toNanos(time));
}
public void unlock() {
sync.release(1);
}
public Condition newCondition() {
return sync.newCondition();
}
public boolean isLocked(){
return sync.isHeldExclusively();
}
public boolean hasQueuedThreads(){
return sync.hasQueuedThreads();
}
}