在上一節(jié)中,
我們已經(jīng)了解了Java多線程編程中常用的關(guān)鍵字synchronized,以及與之相關(guān)的對(duì)象鎖機(jī)制。這一節(jié)中,讓
我們一起來(lái)認(rèn)識(shí)JDK 5中新引入的并發(fā)框架中的鎖機(jī)制。
我想很多購(gòu)買了《Java程序員面試寶典》之類圖書的朋友一定對(duì)下面
這個(gè)面試題感到非常熟悉:
問:請(qǐng)對(duì)比synchronized與java.util.concurrent.locks.Lock
的異同。
答案:主要相同點(diǎn):Lock能完成synchronized所實(shí)現(xiàn)的所有功能
主要不同點(diǎn):Lock有比synchronized更精確的線程語(yǔ)義和更好的性能。synchronized會(huì)自動(dòng)釋放
鎖,而Lock一定要求程序員手工釋放,并且必須在finally從句中釋放。
恩,讓我們先鄙視一下應(yīng)試教育。
言歸正傳,我們先來(lái)看一個(gè)多線程程序。它使用多個(gè)線程對(duì)一個(gè)Student對(duì)象進(jìn)行訪問,改變其中的變量值。
我們首先用傳統(tǒng)的synchronized 機(jī)制來(lái)實(shí)現(xiàn)它:
運(yùn)行結(jié)果:
顯然,在這個(gè)程序中,由于兩段synchronized塊使用了同樣的對(duì)象做為對(duì)象鎖,所以JVM優(yōu)先使剛剛釋放該鎖的線程重新獲得該
鎖。這樣,每個(gè)線程執(zhí)行的時(shí)間是10秒鐘,并且要徹底把兩個(gè)同步塊的動(dòng)作執(zhí)行完畢,才能釋放對(duì)象鎖。這樣,加起來(lái)一共是
30秒。
轉(zhuǎn)載注明出處:http://x- spirit.javaeye.com/、http: //www.aygfsteel.com/zhangwei217245/
我想一定有人會(huì)說(shuō):如果兩段synchronized塊采用兩個(gè)不同的對(duì)象鎖,就可以提高程序的并發(fā)性,并且,這
兩個(gè)對(duì)象鎖應(yīng)該選擇那些被所有線程所共享的對(duì)象。
那么好。我們把第二個(gè)同步塊中的對(duì)象鎖改為student(此處略去代碼,讀
者自己修改),程序運(yùn)行結(jié)果為:
從 修改后的運(yùn)行結(jié)果來(lái)看,顯然,由于同步塊的對(duì)象鎖不同了,三個(gè)線程的執(zhí)行順序也發(fā)生了變化。在一個(gè)線程釋放第一個(gè)同步塊的同步鎖之
后,第二個(gè)線程就可以進(jìn)入第一個(gè)同步塊,而此時(shí),第一個(gè)線程可以繼續(xù)執(zhí)行第二個(gè)同步塊。這樣,整個(gè)執(zhí)行過程中,有10秒鐘
的時(shí)間是兩個(gè)線程同時(shí)工作的。另外十秒鐘分別是第一個(gè)線程執(zhí)行第一個(gè)同步塊的動(dòng)作和最后一個(gè)線程執(zhí)行第二個(gè)同步塊的動(dòng)作。相比較第一
個(gè)例程,整個(gè)程序的運(yùn)行時(shí)間節(jié)省了1/3。細(xì)心的讀者不難總結(jié)出優(yōu)化前后的執(zhí)行時(shí)間比例公式:(n+1)/2n,其中n為
線程數(shù)。如果線程數(shù)趨近于正無(wú)窮,則程序執(zhí)行效率的提高會(huì)接近50%。而如果一個(gè)線程的執(zhí)行階段被分割成m個(gè)
synchronized塊,并且每個(gè)同步塊使用不同的對(duì)象鎖,而同步塊的執(zhí)行時(shí)間恒定,則執(zhí)行時(shí)間比例公式可以寫作:((m-
1)n+1)/mn那么當(dāng)m趨于無(wú)窮大時(shí),線程數(shù)n趨近于無(wú)窮大,則程序執(zhí)行效率的提升幾乎可以達(dá)到100%。(顯然,我
們不能按照理想情況下的數(shù)學(xué)推導(dǎo)來(lái)給BOSS發(fā)報(bào)告,不過通過這樣的數(shù)學(xué)推導(dǎo),至少我們看到了提高多線程程序并發(fā)性的一種方案,而
這種方案至少具備數(shù)學(xué)上的可行性理論支持。)
轉(zhuǎn)載注明出處:http://x- spirit.javaeye.com/、http: //www.aygfsteel.com/zhangwei217245/
可見,使用不同的對(duì)象鎖,在不同的同步塊中完成任務(wù),可以使性能大大提升。
很多人看到這不禁要問:這和新的Lock框 架有什么關(guān)系?
別著急。我們這就來(lái)看一看。
synchronized塊的確不錯(cuò),但是他有一些功能性的限制:
1. 它無(wú)法中斷一個(gè)正在等候獲得鎖的線程,也無(wú)法通過投票得到鎖,如果不想等下去,也就沒法得到鎖。
2.synchronized
塊對(duì)于鎖的獲得和釋放是在相同的堆棧幀中進(jìn)行的。多數(shù)情況下,這沒問題(而且與異常處理交互得很好),但是,確實(shí)存在一些更適合使用
非塊結(jié)構(gòu)鎖定的情況。
轉(zhuǎn)載注明出處:http://x- spirit.javaeye.com/、http: //www.aygfsteel.com/zhangwei217245/
java.util.concurrent.lock 中的 Lock 框架是鎖定的一個(gè)抽象,它允許把鎖定的實(shí)現(xiàn)作為 Java 類,而不是作為語(yǔ)言的特性來(lái)實(shí)現(xiàn)。這就為 Lock 的多種實(shí)現(xiàn)留下了空間,各種實(shí)現(xiàn)可能有不同的調(diào)度算法、性能特性或者鎖定語(yǔ)義。
JDK 官方文檔中提到:
ReentrantLock是“一個(gè)可重入的互斥鎖 Lock,它具有與使用 synchronized 方法和語(yǔ)句所訪問的隱式監(jiān)視器鎖相同的一些基本行為和語(yǔ)義,但功能更強(qiáng)大。
ReentrantLock 將由最近成功獲得鎖,并且還沒有釋放該鎖的線程所擁有。當(dāng)鎖沒有被另一個(gè)線程所擁有時(shí),調(diào)用 lock
的線程將成功獲取該鎖并返回。如果當(dāng)前線程已經(jīng)擁有該鎖,此方法將立即返回。可以使用 isHeldByCurrentThread() 和
getHoldCount() 方法來(lái)檢查此情況是否發(fā)生。 ”
簡(jiǎn)單來(lái)說(shuō),ReentrantLock有一個(gè)與鎖相關(guān)的獲取計(jì)
數(shù)器,如果擁有鎖的某個(gè)線程再次得到鎖,那么獲取計(jì)數(shù)器就加1,然后鎖需要被釋放兩次才能獲得真正釋放。這模仿了
synchronized 的語(yǔ)義;如果線程進(jìn)入由線程已經(jīng)擁有的監(jiān)控器保護(hù)的 synchronized
塊,就允許線程繼續(xù)進(jìn)行,當(dāng)線程退出第二個(gè)(或者后續(xù)) synchronized 塊的時(shí)候,不釋放鎖,只有線程退出它進(jìn)入的監(jiān)控器保護(hù)的第一個(gè)
synchronized 塊時(shí),才釋放鎖。
轉(zhuǎn)載注明出處:http://x- spirit.javaeye.com/、http: //www.aygfsteel.com/zhangwei217245/
ReentrantLock 類(重入鎖)實(shí)現(xiàn)了 Lock ,它擁有與 synchronized 相同的并發(fā)性和內(nèi)存語(yǔ)義,但是添加了類似鎖投票、定時(shí)鎖等候和可中斷鎖等候的一些特性。此外,它還提供了在激烈爭(zhēng)用情況下更佳的性
能。(換句話說(shuō),當(dāng)許多線程都想訪問共享資源時(shí),JVM 可以花更少的時(shí)候來(lái)調(diào)度線程,把更多時(shí)間用在執(zhí)行線程上。)
我們把 上面的例程改造一下:
從上面這個(gè) 程序我們看到:
對(duì)象鎖的獲得和釋放是由手工編碼完成的,所以獲得鎖和釋放鎖的時(shí)機(jī)比使用同步塊具有更好的可定制性。并
且通過程序的運(yùn)行結(jié)果(運(yùn)行結(jié)果忽略,請(qǐng)讀者根據(jù)例程自行觀察),我們可以發(fā)現(xiàn),和使用同步塊的版本相比,結(jié)果是相同的。
轉(zhuǎn)載注明出處:http://x- spirit.javaeye.com/、http: //www.aygfsteel.com/zhangwei217245/
這說(shuō)明兩點(diǎn)問題:
1. 新的ReentrantLock的確實(shí)現(xiàn)了和同步塊相同的語(yǔ)義功能。而對(duì)象鎖的獲得和釋放都可以由編碼
人員自行掌握。
2. 使用新的ReentrantLock,免去了為同步塊放置合適的對(duì)象鎖所要進(jìn)行的考量。
3. 使用新的ReentrantLock,最佳的實(shí)踐就是結(jié)合try/finally塊來(lái)進(jìn)行。在try塊之前使用lock方法,而
在finally中使用unlock方法。
轉(zhuǎn)載注明出處:http://x- spirit.javaeye.com/、http: //www.aygfsteel.com/zhangwei217245/
細(xì)心的讀者又發(fā)現(xiàn)了:
在我們的例程中,創(chuàng)建ReentrantLock實(shí)例的時(shí)候,我們的構(gòu)造函數(shù)里面?zhèn)鬟f的參數(shù)是false。那么如果傳遞
true又回是什么結(jié)果呢?這里面又有什么奧秘呢?
請(qǐng)看本節(jié)的續(xù) ———— Fair or Unfair? It is a question...
我想很多購(gòu)買了《Java程序員面試寶典》
問:請(qǐng)對(duì)比synchronized與java.util.
答案:主要相同點(diǎn):
主要不同點(diǎn):
恩,讓我們先鄙視一下應(yīng)試教育。
言歸正傳,我們先來(lái)看一個(gè)多線程程序。
public class ThreadDemo implements Runnable {
class Student {
private int age = 0;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Student student = new Student();
int count = 0;
public static void main(String[] args) {
ThreadDemo td = new ThreadDemo();
Thread t1 = new Thread(td, "a");
Thread t2 = new Thread(td, "b");
Thread t3 = new Thread(td, "c");
t1.start();
t2.start();
t3.start();
}
public void run() {
accessStudent();
}
public void accessStudent() {
String currentThreadName = Thread.currentThread().getName();
System.out.println(currentThreadName + " is running!");
synchronized (this) {//(1)使用同一個(gè)ThreadDemo對(duì)象作為同步鎖
System.out.println(currentThreadName + " got lock1@Step1!");
try {
count++;
Thread.sleep(5000);
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println(currentThreadName + " first Reading count:" + count);
}
}
System.out.println(currentThreadName + " release lock1@Step1!");
synchronized (this) {//(2)使用同一個(gè)ThreadDemo對(duì)象作為同步鎖
System.out.println(currentThreadName + " got lock2@Step2!");
try {
Random random = new Random();
int age = random.nextInt(100);
System.out.println("thread " + currentThreadName + " set age to:" + age);
this.student.setAge(age);
System.out.println("thread " + currentThreadName + " first read age is:" + this.student.getAge());
Thread.sleep(5000);
} catch (Exception ex) {
ex.printStackTrace();
} finally{
System.out.println("thread " + currentThreadName + " second read age is:" + this.student.getAge());
}
}
System.out.println(currentThreadName + " release lock2@Step2!");
}
}
轉(zhuǎn)載注明出處:http://x-
spirit.javaeye.com/、http:
//www.aygfsteel.com/zhangwei217245/
class Student {
private int age = 0;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Student student = new Student();
int count = 0;
public static void main(String[] args) {
ThreadDemo td = new ThreadDemo();
Thread t1 = new Thread(td, "a");
Thread t2 = new Thread(td, "b");
Thread t3 = new Thread(td, "c");
t1.start();
t2.start();
t3.start();
}
public void run() {
accessStudent();
}
public void accessStudent() {
String currentThreadName = Thread.currentThread().getName();
System.out.println(currentThreadName + " is running!");
synchronized (this) {//(1)使用同一個(gè)ThreadDemo對(duì)象作為同步鎖
System.out.println(currentThreadName + " got lock1@Step1!");
try {
count++;
Thread.sleep(5000);
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println(currentThreadName + " first Reading count:" + count);
}
}
System.out.println(currentThreadName + " release lock1@Step1!");
synchronized (this) {//(2)使用同一個(gè)ThreadDemo對(duì)象作為同步鎖
System.out.println(currentThreadName + " got lock2@Step2!");
try {
Random random = new Random();
int age = random.nextInt(100);
System.out.println("thread " + currentThreadName + " set age to:" + age);
this.student.setAge(age);
System.out.println("thread " + currentThreadName + " first read age is:" + this.student.getAge());
Thread.sleep(5000);
} catch (Exception ex) {
ex.printStackTrace();
} finally{
System.out.println("thread " + currentThreadName + " second read age is:" + this.student.getAge());
}
}
System.out.println(currentThreadName + " release lock2@Step2!");
}
}
運(yùn)行結(jié)果:
a is running!
a got lock1@Step1!
b is running!
c is running!
a first Reading count:1
a release lock1@Step1!
a got lock2@Step2!
thread a set age to:76
thread a first read age is:76
thread a second read age is:76
a release lock2@Step2!
c got lock1@Step1!
c first Reading count:2
c release lock1@Step1!
c got lock2@Step2!
thread c set age to:35
thread c first read age is:35
thread c second read age is:35
c release lock2@Step2!
b got lock1@Step1!
b first Reading count:3
b release lock1@Step1!
b got lock2@Step2!
thread b set age to:91
thread b first read age is:91
thread b second read age is:91
b release lock2@Step2!
成功生成(總時(shí)間:30 秒)
a got lock1@Step1!
b is running!
c is running!
a first Reading count:1
a release lock1@Step1!
a got lock2@Step2!
thread a set age to:76
thread a first read age is:76
thread a second read age is:76
a release lock2@Step2!
c got lock1@Step1!
c first Reading count:2
c release lock1@Step1!
c got lock2@Step2!
thread c set age to:35
thread c first read age is:35
thread c second read age is:35
c release lock2@Step2!
b got lock1@Step1!
b first Reading count:3
b release lock1@Step1!
b got lock2@Step2!
thread b set age to:91
thread b first read age is:91
thread b second read age is:91
b release lock2@Step2!
成功生成(總時(shí)間:30 秒)
顯然,在這個(gè)程序中,
轉(zhuǎn)載注明出處:http://x- spirit.javaeye.com/、http: //www.aygfsteel.com/zhangwei217245/
我想一定有人會(huì)說(shuō):
那么好。我們把第二個(gè)同步塊中的對(duì)象鎖改為student(
a is running!
a got lock1@Step1!
b is running!
c is running!
a first Reading count:1
a release lock1@Step1!
a got lock2@Step2!
thread a set age to:73
thread a first read age is:73
c got lock1@Step1!
thread a second read age is:73
a release lock2@Step2!
c first Reading count:2
c release lock1@Step1!
c got lock2@Step2!
thread c set age to:15
thread c first read age is:15
b got lock1@Step1!
thread c second read age is:15
c release lock2@Step2!
b first Reading count:3
b release lock1@Step1!
b got lock2@Step2!
thread b set age to:19
thread b first read age is:19
thread b second read age is:19
b release lock2@Step2!
成功生成(總時(shí)間:21 秒)
a got lock1@Step1!
b is running!
c is running!
a first Reading count:1
a release lock1@Step1!
a got lock2@Step2!
thread a set age to:73
thread a first read age is:73
c got lock1@Step1!
thread a second read age is:73
a release lock2@Step2!
c first Reading count:2
c release lock1@Step1!
c got lock2@Step2!
thread c set age to:15
thread c first read age is:15
b got lock1@Step1!
thread c second read age is:15
c release lock2@Step2!
b first Reading count:3
b release lock1@Step1!
b got lock2@Step2!
thread b set age to:19
thread b first read age is:19
thread b second read age is:19
b release lock2@Step2!
成功生成(總時(shí)間:21 秒)
從 修改后的運(yùn)行結(jié)果來(lái)看,顯然,由于同步塊的對(duì)象鎖不同了,
轉(zhuǎn)載注明出處:http://x- spirit.javaeye.com/、http: //www.aygfsteel.com/zhangwei217245/
可見,使用不同的對(duì)象鎖,在不同的同步塊中完成任務(wù),
很多人看到這不禁要問:這和新的Lock框 架有什么關(guān)系?
別著急。我們這就來(lái)看一看。
synchronized塊的確不錯(cuò),
1. 它無(wú)法中斷一個(gè)正在等候獲得鎖的線程,
2.
轉(zhuǎn)載注明出處:http://x- spirit.javaeye.com/、http: //www.aygfsteel.com/zhangwei217245/
java.util.concurrent.lock 中的 Lock 框架是鎖定的一個(gè)抽象,它允許把鎖定的實(shí)現(xiàn)作為 Java 類,而不是作為語(yǔ)言的特性來(lái)實(shí)現(xiàn)。這就為 Lock 的多種實(shí)現(xiàn)留下了空間,各種實(shí)現(xiàn)可能有不同的調(diào)度算法、
JDK 官方文檔中提到:
ReentrantLock是“一個(gè)可重入的互斥鎖 Lock,它具有與使用 synchronized 方法和語(yǔ)句所訪問的隱式監(jiān)視器鎖相同的一些基本行為和語(yǔ)義,
ReentrantLock 將由最近成功獲得鎖,并且還沒有釋放該鎖的線程所擁有。
簡(jiǎn)單來(lái)說(shuō),
轉(zhuǎn)載注明出處:http://x- spirit.javaeye.com/、http: //www.aygfsteel.com/zhangwei217245/
ReentrantLock 類(重入鎖)實(shí)現(xiàn)了 Lock ,它擁有與 synchronized 相同的并發(fā)性和內(nèi)存語(yǔ)義,但是添加了類似鎖投票、
我們把 上面的例程改造一下:
public class ThreadDemo implements Runnable {
class Student {
private int age = 0;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Student student = new Student();
int count = 0;
ReentrantLock lock1 = new ReentrantLock(false);
ReentrantLock lock2 = new ReentrantLock(false);
public static void main(String[] args) {
ThreadDemo td = new ThreadDemo();
for (int i = 1; i <= 3; i++) {
Thread t = new Thread(td, i + "");
t.start();
}
}
public void run() {
accessStudent();
}
public void accessStudent() {
String currentThreadName = Thread.currentThread().getName();
System.out.println(currentThreadName + " is running!");
lock1.lock();//使用重入鎖
System.out.println(currentThreadName + " got lock1@Step1!");
try {
count++;
Thread.sleep(5000);
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println(currentThreadName + " first Reading count:" + count);
lock1.unlock();
System.out.println(currentThreadName + " release lock1@Step1!");
}
lock2.lock();//使用另外一個(gè)不同的重入鎖
System.out.println(currentThreadName + " got lock2@Step2!");
try {
Random random = new Random();
int age = random.nextInt(100);
System.out.println("thread " + currentThreadName + " set age to:" + age);
this.student.setAge(age);
System.out.println("thread " + currentThreadName + " first read age is:" + this.student.getAge());
Thread.sleep(5000);
} catch (Exception ex) {
ex.printStackTrace();
} finally {
System.out.println("thread " + currentThreadName + " second read age is:" + this.student.getAge());
lock2.unlock();
System.out.println(currentThreadName + " release lock2@Step2!");
}
}
}
class Student {
private int age = 0;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Student student = new Student();
int count = 0;
ReentrantLock lock1 = new ReentrantLock(false);
ReentrantLock lock2 = new ReentrantLock(false);
public static void main(String[] args) {
ThreadDemo td = new ThreadDemo();
for (int i = 1; i <= 3; i++) {
Thread t = new Thread(td, i + "");
t.start();
}
}
public void run() {
accessStudent();
}
public void accessStudent() {
String currentThreadName = Thread.currentThread().getName();
System.out.println(currentThreadName + " is running!");
lock1.lock();//使用重入鎖
System.out.println(currentThreadName + " got lock1@Step1!");
try {
count++;
Thread.sleep(5000);
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println(currentThreadName + " first Reading count:" + count);
lock1.unlock();
System.out.println(currentThreadName + " release lock1@Step1!");
}
lock2.lock();//使用另外一個(gè)不同的重入鎖
System.out.println(currentThreadName + " got lock2@Step2!");
try {
Random random = new Random();
int age = random.nextInt(100);
System.out.println("thread " + currentThreadName + " set age to:" + age);
this.student.setAge(age);
System.out.println("thread " + currentThreadName + " first read age is:" + this.student.getAge());
Thread.sleep(5000);
} catch (Exception ex) {
ex.printStackTrace();
} finally {
System.out.println("thread " + currentThreadName + " second read age is:" + this.student.getAge());
lock2.unlock();
System.out.println(currentThreadName + " release lock2@Step2!");
}
}
}
從上面這個(gè) 程序我們看到:
對(duì)象鎖的獲得和釋放是由手工編碼完成的,
轉(zhuǎn)載注明出處:http://x- spirit.javaeye.com/、http: //www.aygfsteel.com/zhangwei217245/
這說(shuō)明兩點(diǎn)問題:
1. 新的ReentrantLock的確實(shí)現(xiàn)了和同步塊相同的語(yǔ)義功
2. 使用新的ReentrantLock,
3. 使用新的ReentrantLock,
轉(zhuǎn)載注明出處:http://x- spirit.javaeye.com/、http: //www.aygfsteel.com/zhangwei217245/
細(xì)心的讀者又發(fā)現(xiàn)了:
在我們的例程中,創(chuàng)建ReentrantLock實(shí)例的時(shí)候,
請(qǐng)看本節(jié)的續(xù) ———— Fair or Unfair? It is a question...
使用 synchronized 其實(shí)仍由操作系統(tǒng)來(lái)調(diào)度線程的優(yōu)先級(jí),Lock 則是掌控在 java 程序中
Lock 用 lock() 和 unlock() 取代了 JVM 的 monitorenter 和 monitorexit 操作指令。
感謝黃鶯的深入分析~~~
不清楚你怎樣推出你的公式的。不過博客上談這個(gè)確實(shí)不方便。有時(shí)間可以面談。呵呵。。。
有一個(gè)問題,如果在lock方法之后在try之前出現(xiàn)一些異常,會(huì)不會(huì)導(dǎo)致lock沒有unlock而出現(xiàn)問題。
為什么一定要在lock方法之后和try塊之前加入一些有可能拋出異常的語(yǔ)句,而不對(duì)這些語(yǔ)句進(jìn)行異常捕獲呢?這樣的編碼習(xí)慣難道可取嗎?
或者如果你覺得可以的話,也可以在try塊的第一行就寫lock方法。
這個(gè)與JVM實(shí)現(xiàn)有關(guān)吧?
樓主哪里得來(lái)的結(jié)論,請(qǐng)指教
請(qǐng)參閱:http://flierlu.spaces.live.com/Blog/cns!3B002B2C3F5C8E36!160.entry
文中介紹了一種基于預(yù)期的鎖定策略。
文中講到:
“事實(shí)上,JVM 可以根據(jù)運(yùn)行時(shí)信息選擇性合并同類型鎖。隨著現(xiàn)在機(jī)器自動(dòng)代碼生成的廣泛引用,可以預(yù)期這種基于行為對(duì)鎖進(jìn)行合并的思路會(huì)非常有用。“、
“這些問題(同步很慢、把類和方法聲明為final可以提高性能、不可變對(duì)象是性能毒藥)的出現(xiàn),往往是因?yàn)槭褂谜邔?duì) JVM 的實(shí)現(xiàn)和優(yōu)化思路不熟悉導(dǎo)致的。實(shí)際上 HotSpot 自從 JDK 1.3 版本以后,實(shí)際上有了非常大的進(jìn)步,無(wú)論是從功能還是性能上,都已經(jīng)遠(yuǎn)遠(yuǎn)超出了某些人的預(yù)期。而在可以預(yù)見的 Mustang 和 Dolphin 中,更高級(jí)和動(dòng)態(tài)的優(yōu)化還會(huì)不斷加入進(jìn)來(lái),并從 JVM 一級(jí)對(duì)應(yīng)用產(chǎn)生透明的性能提升。”
實(shí)際上,看一下我在本篇文章中的第一個(gè)例程的運(yùn)行結(jié)果,你就會(huì)發(fā)現(xiàn),JVM的確是從語(yǔ)義上合并了兩段同步塊的鎖。而從常理上講,這樣的鎖分配策略在保證線程運(yùn)行流暢性方面是相對(duì)比較優(yōu)化的方案。