java重入锁_java并发编程:可重入锁是什么?
釋義
廣義上的可重入鎖指的是可重復(fù)可遞歸調(diào)用的鎖,在外層使用鎖之后,在內(nèi)層仍然可以使用,并且不發(fā)生死鎖(前提得是同一個(gè)對象或者class),這樣的鎖就叫做可重入鎖。ReentrantLock和synchronized都是可重入鎖,下面是一個(gè)用synchronized實(shí)現(xiàn)的例子:
public class ReentrantTest implements Runnable {
public synchronized void get() {
System.out.println(Thread.currentThread().getName());
set();
}
public synchronized void set() {
System.out.println(Thread.currentThread().getName());
}
public void run() {
get();
}
public static void main(String[] args) {
ReentrantTest rt = new ReentrantTest();
for(;;){
new Thread(rt).start();
}
}
}
整個(gè)過程沒有發(fā)生死鎖的情況,截取一部分輸出結(jié)果如下:
Thread-8492
Thread-8492
Thread-8494
Thread-8494
Thread-8495
Thread-8495
Thread-8493
Thread-8493
set()和get()同時(shí)輸出了線程名稱,表明即使遞歸使用synchronized也沒有發(fā)生死鎖,證明其是可重入的。
不可重入鎖
不可重入鎖,與可重入鎖相反,不可遞歸調(diào)用,遞歸調(diào)用就發(fā)生死鎖??吹揭粋€(gè)經(jīng)典的講解,使用自旋鎖來模擬一個(gè)不可重入鎖,代碼如下:
import java.util.concurrent.atomic.AtomicReference;
public class UnreentrantLock {
private AtomicReference owner = new AtomicReference();
public void lock() {
Thread current = Thread.currentThread();
//這句是很經(jīng)典的“自旋”語法,AtomicInteger中也有
for (;;) {
if (!owner.compareAndSet(null, current)) {
return;
}
}
}
public void unlock() {
Thread current = Thread.currentThread();
owner.compareAndSet(current, null);
}
}
代碼也比較簡單,使用原子引用來存放線程,同一線程兩次調(diào)用lock()方法,如果不執(zhí)行unlock()釋放鎖的話,第二次調(diào)用自旋的時(shí)候就會(huì)產(chǎn)生死鎖,這個(gè)鎖就不是可重入的,而實(shí)際上同一個(gè)線程不必每次都去釋放鎖再來獲取鎖,這樣的調(diào)度切換是很耗資源的。稍微改一下,把它變成一個(gè)可重入鎖:
import java.util.concurrent.atomic.AtomicReference;
public class UnreentrantLock {
private AtomicReference owner = new AtomicReference();
private int state = 0;
public void lock() {
Thread current = Thread.currentThread();
if (current == owner.get()) {
state++;
return;
}
//這句是很經(jīng)典的“自旋”式語法,AtomicInteger中也有
for (;;) {
if (!owner.compareAndSet(null, current)) {
return;
}
}
}
public void unlock() {
Thread current = Thread.currentThread();
if (current == owner.get()) {
if (state != 0) {
state--;
} else {
owner.compareAndSet(current, null);
}
}
}
}
在執(zhí)行每次操作之前,判斷當(dāng)前鎖持有者是否是當(dāng)前對象,采用state計(jì)數(shù),不用每次去釋放鎖。
ReentrantLock中可重入鎖實(shí)現(xiàn)
這里看非公平鎖的鎖獲取方法:
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(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;
}
在AQS中維護(hù)了一個(gè)private volatile int state來計(jì)數(shù)重入次數(shù),避免了頻繁的持有釋放操作,這樣既提升了效率,又避免了死鎖。
超強(qiáng)干貨來襲 云風(fēng)專訪:近40年碼齡,通宵達(dá)旦的技術(shù)人生總結(jié)
以上是生活随笔為你收集整理的java重入锁_java并发编程:可重入锁是什么?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java的css的块_CSS块宽度不大于
- 下一篇: java mysbatis select