读立写生 2018-01-16
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author admin
* @date 2018/1/16 12:16
* ReentrantLock 可重入锁:
* 1、启动两个线程,线程A获取锁,然后执行;同时线程B进来后,一直阻塞,直到线程A释放锁之后,线程B才接着执行
*/
public class ReentrantLockTest {
ReentrantLock lock = new ReentrantLock();
public void reentrantLockRun1(String threadName) {
System.out.println(threadName + "进入");
lock.lock();
System.out.println(threadName + "方法被锁");
try {
System.out.println(threadName + "方法执行");
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
System.out.println(threadName + "锁被释放");
}
}
public static void main(String[] args) {
ReentrantLockTest rltest = new ReentrantLockTest();
Thread thread = new Thread() {
public void run() {
rltest.reentrantLockRun1("线程A");
}
};
thread.start();
Thread thread2 = new Thread() {
public void run() {
rltest.reentrantLockRun1("线程B");
}
};
thread2.start();
}
}
运行结果:
线程A进入
线程A方法被锁
线程A方法执行
线程B进入
线程A锁被释放
线程B方法被锁
线程B方法执行
线程B锁被释放import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author admin
* @date 2018/1/16 12:16
* ReentrantLock 可重入锁:
* 1、启动两个线程,线程A获取锁,然后执行,不释放锁,接着线程A再调用reentrantLockRun2,不需要阻塞,接着执行,最后释放锁;说明同一个线程对ReentrantLock可重复获取
* 2、线程B在这个过程中一直阻塞,等到线程A把所有的锁释放完之后,再获取锁,执行方法,最后释放锁
*/
public class ReentrantLockTest2 {
ReentrantLock lock = new ReentrantLock();
public ReentrantLock reentrantLockRun1(String threadName) {
System.out.println(threadName + "进入");
lock.lock();
System.out.println(threadName + "方法被锁");
try {
System.out.println(threadName + "方法执行");
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return lock;
}
public ReentrantLock reentrantLockRun2(String threadName) {
System.out.println(threadName + "进入");
lock.lock();
System.out.println(threadName + "方法被锁");
try {
System.out.println(threadName + "方法执行");
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return lock;
}
public static void main(String[] args) {
ReentrantLockTest2 rltest = new ReentrantLockTest2();
Thread thread = new Thread() {
public void run() {
ReentrantLock lock1 = rltest.reentrantLockRun1("线程A");
ReentrantLock lock2 = rltest.reentrantLockRun2("线程A2");
lock1.unlock();
System.out.println("线程A释放锁");
lock2.unlock();
System.out.println("线程A2释放锁");
}
};
thread.start();
Thread thread2 = new Thread() {
public void run() {
ReentrantLock lock = rltest.reentrantLockRun1("线程B");
lock.unlock();
System.out.println("线程B释放锁");
}
};
thread2.start();
}
}
运行结果:
线程A进入
线程A方法被锁
线程A方法执行
线程B进入
线程A2进入
线程A2方法被锁
线程A2方法执行
线程A释放锁
线程A2释放锁
线程B方法被锁
线程B方法执行
线程B释放锁根据源码发现:维护了这个可见性变量state ;同一个线程对可重入锁体现用state标记作累加,int nextc = c + acquires;
private volatile int state;
public void lock() {<br />sync.lock();<br />}public final void acquire(int arg) {<br />if (!tryAcquire(arg) &&<br /> acquireQueued(addWaiter(Node.EXCLUSIVE), arg))<br />selfInterrupt();<br />}<br /><br />// 判断是不是第一次获取锁,如果是操作state=1;否则判断是不是同一个线程如果是state+1,如果不是同一个线程直接返回falseprotected final boolean tryAcquire(int acquires) {<br />final Thread current = Thread.currentThread();<br /> int c = getState();<br /> if (c == 0) {<br />if (!hasQueuedPredecessors() &&<br /> compareAndSetState(0, acquires)) {<br /> setExclusiveOwnerThread(current);<br /> return true;<br /> }<br /> }<br />else if (current == getExclusiveOwnerThread()) {<br />int nextc = c + acquires;<br /> if (nextc < 0)<br />throw new Error("Maximum lock count exceeded");<br /> setState(nextc);<br /> return true;<br /> }<br />return false;<br /> }<br />}<br />// 大概就是用一个链表来维护等待线程<br />final boolean acquireQueued(final Node node, int arg) {<br />boolean failed = true;<br /> try {<br />boolean interrupted = false;<br /> for (;;) {<br />final Node p = node.predecessor();<br /> if (p == head && tryAcquire(arg)) {<br /> setHead(node);<br /> p.next = null; // help GC<br /> failed = false;<br /> return interrupted;<br /> }<br />if (shouldParkAfterFailedAcquire(p, node) &&<br /> parkAndCheckInterrupt())<br /> interrupted = true;<br /> }<br /> } finally {<br />if (failed)<br /> cancelAcquire(node);<br /> }<br />}