ReentrantLock中中断锁和非中断锁源码分析

最近读了Java并发编程的艺术记录一下

https://www.cnblogs.com/daydaynobug/p/6752837.html
关于AQS的讲解

尝试获取一个内部锁的操作(进入一个 synchronized 块)是不能被中断的

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才会响应它自己的中断

ReentrantLock的中断操作lockInterruptibly()

下面是lockInterruptibly()的代码

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()的代码

有两个实现类实现了lock()方法,NonfairSync非公平锁和FairSync公平锁

NonfairSync

	final void lock() {
     
	    if (compareAndSetState(0, 1))
	        setExclusiveOwnerThread(Thread.currentThread());
	    else
	        acquire(1);
	}

FairSync

	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;只是把中断状态记录了下来等得到同步状态后再处理

你可能感兴趣的:(java并发编程,JavaSE)