最近读了Java并发编程的艺术记录一下
https://www.cnblogs.com/daydaynobug/p/6752837.html
关于AQS的讲解
public class WriterReader {
private Object lock;
public WriterReader() {
lock = this;
}
public void write() {
synchronized (lock) {
long startTime = System.currentTimeMillis();
System.out.println("开始往这个buff写入数据…");
for (; ; )// 模拟要处理很长时间
{
if (System.currentTimeMillis()
- startTime > Integer.MAX_VALUE) {
System.out.println("终于写完了");
break;
}
if (Thread.currentThread().isInterrupted()) {
System.out.println("被中断");
System.out.println(Thread.interrupted());
System.out.println(Thread.interrupted());
System.out.println(Thread.interrupted());
break;
}
System.out.println("写.........");
}
}
}
public void read() {
synchronized (lock) {
System.out.println("从这个buff读数据");
if (Thread.currentThread().isInterrupted()) {
for (int i = 0; i < 10; i++) {
System.out.println("read被中断");
}
}
}
}
}
public class InterruptDemo {
public static void main(String[] args) throws InterruptedException {
Object lock = new Object();
WriterReader writerReader = new WriterReader();
Thread writer = new Thread(new Runnable() {
@Override
public void run() {
writerReader.write();
}
});
writer.start();
Thread reader = new Thread(new Runnable() {
@Override
public void run() {
writerReader.read();
}
});
reader.start();
Thread.sleep(100);
//这里中断写线程可以被立即响应,writer正在运行
//writer.interrupt();
//但是处于阻塞态的线程不可以立即响应,可以看到在writer运行结束后reader的中断情况才改变
reader.interrupt();
Thread.sleep(10000);
System.out.println("reader.isInterrupted():" + reader.isInterrupted());
writer.interrupt();
}
}
当把reader中断后发现没有起作用,只有writer被中断结束后,reader才会响应它自己的中断
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
public final void acquireInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (!tryAcquire(arg))
doAcquireInterruptibly(arg);
}
private void doAcquireInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
可以看到的是如果监测到中断就直接throw new InterruptedException();
抛出来了,所以可以响应中断
有两个实现类实现了lock()方法,NonfairSync非公平锁和FairSync公平锁
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
final void lock() {
acquire(1);
}
非公平锁就是不等排在前面的,在lock时直接尝试去获取state来抢占运行时间,不行的化就排队。然后他们都通过acquire(1);获取同步状态
//AQS的acquire方法
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
父类AQS通过调用子类的tryAcquire(arg)来尝试获取同步状态
ReentrantLock的非公平锁实现为
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSet
State(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
可以看到nonfairTryAcquire方法在得知c==0的情况下没有考虑自己排在哪就直接去尝试得到运行资源了compareAndSetState(0, acquires)
ReentrantLock的公平锁实现为
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
公平锁先看自己前面有没有排队的人在尝试调用compareAndSetState(0, acquires)获取资源
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
前面扯远了,下面如果没有得到同步状态,那么就要acquireQueued
了
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);
}
}
可以看到这里和lockInterruptibly()处理中断的不一样了interrupted = true;只是把中断状态记录了下来等得到同步状态后再处理