队列同步器
队列同步器AbstractQueuedSynchronizer,是用来构建锁或者其他同步组件的基础框架,它使用了一个int类型的成员变量来表示当前的同步状态,例如1表示有线程在占用锁,0表示没有线程占用该锁。它采用了FIFO的队列来实现。
拿独占锁来说,队列中有多个节点(Node),每个节点代表每个线程。而这个队列的头部(head)会放在一个同步器中,表示其头部正在占用该线程。
而其他的节点都会处于一个自旋的状态(其实就是一个for循环),以下列出同步队列器的源码。
/**
* Acquires in exclusive uninterruptible mode for thread already in
* queue. Used by condition wait methods as well as acquire.
*
* @param node the node
* @param arg the acquire argument
* @return {@code true} if interrupted while waiting
*/
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
每个非头结点的Node,会一直处于for循环中,判断这个锁是否被释放。当然,当head节点释放资源之后,head节点的next节点会取代head节点,其会加入到同步器中,占有这个锁。
排它锁的实现
package com.yangyang.thread;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
/**
* 要想创建一个锁,那么首先继承Lock接口,
* 因为同步机制还需要同步队列来实现,保证其操作的原子性。
* 因此我们还必须要创建一个内部类,来实现一个同步队列。
*/
public class Mutex implements Lock {
/**
* 我们在这里实现一个排他锁,因此我们必须要重写
* tryAcquire(int arg):尝试获取同步状态(arg为1表示占用锁)
* tryRelease(int arg):尝试释放同步状态
* isHeldExclusively():是否处于占用状态
*/
// 为什么要写成静态的内部类呢?因为我们在锁的时候肯定需要一个类属性来进行,不然每个对象都有一个没效果。
private static class Syn extends AbstractQueuedSynchronizer{
@Override
protected boolean tryAcquire(int arg) {
// 尝试占用锁,使用CAS(compareAndSwap)原子性的操作
if(compareAndSetState(0,1)){
// 操作成功,那么设置为独占锁
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
@Override
protected boolean tryRelease(int arg) {
// 试图释放锁,如果当前状态为没有线程占用,那么抛出异常
if(getState()==0) throw new IllegalThreadStateException();//
setExclusiveOwnerThread(null);
setState(0);
return true;
}
@Override
protected boolean isHeldExclusively() {
return getState()==1;
}
Condition newCondition(){
return new ConditionObject();
}
}
private final Syn syn = new Syn();
/**
* 请求一个独占锁
*/
@Override
public void lock() {
syn.acquire(1);
}
@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() {
syn.release(0);// 这个1参数没有意义,因为我们在重写的时候就没有使用到这个参数,但是书上是这么写的不知道是写错了还是怎么.
// 所以我还是改为0吧,因为0表示这个没有获得同步状态。
}
@Override
public Condition newCondition() {
return syn.newCondition();
}
}
class TestMutex{
public static void main(String[] args) {
// 创建两个线程测试一下
Mutex lock = new Mutex();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
lock.lock();//加锁
try{
for (int i = 0 ; i < 10; i++){
System.out.println("t1 "+i);
}
}finally {
lock.unlock();//释放锁
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
lock.lock();//加锁
try{
for (int i = 0 ; i < 10; i++){
System.out.println("t2 "+i);
}
}finally {
lock.unlock();//释放锁
}
}
});
t1.start();
t2.start();
}
}