Java并發(fā)編程的藝術(shù)pdf txt mobi讀書(shū)筆記
如何解決資源限制的問(wèn)題:對(duì)于軟件資源限制嚎尤,可以考慮使用資源池將資源復(fù)用。比如使用連接池將數(shù)據(jù)庫(kù)和Socket連接復(fù)用伍宦,或者在調(diào)用對(duì)方webservice接口獲取數(shù)據(jù)時(shí)芽死,只建立一個(gè)連接。
作者:方騰飛
Java并發(fā)編程的藝術(shù)pdf txt mobi下載
http://www.txtepub.com/2322.html
閱讀感悟:鎖是個(gè)非常有用的工具次洼,運(yùn)用場(chǎng)景非常多关贵,因?yàn)樗褂闷饋?lái)非常簡(jiǎn)單,而且易于理解卖毁。但同時(shí)它也會(huì)帶來(lái)一些困擾揖曾,那就是可能會(huì)引起死鎖,一旦產(chǎn)生死鎖亥啦,就會(huì)造成系統(tǒng)功能不可用炭剪。讓我們先來(lái)看一段代碼,這段代碼會(huì)引起死鎖翔脱,使線程t1和線程t2互相等待對(duì)方釋放鎖奴拦。
public class DeadLockDemo {
? ? privat static String A = "A";
? ? private static String B = "B";
? ? public static void main(String[] args) {
? ? ? ? ? ? new DeadLockDemo().deadLock();
? ? }
? ? private void deadLock() {
? ? ? ? ? ? Thread t1 = new Thread(new Runnable() {
? ? ? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? ? ? publicvoid run() {
? ? ? ? ? ? ? ? ? ? ? ? ? ? synchronized (A) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? try { Thread.currentThread().sleep(2000);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? } catch (InterruptedException e) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? e.printStackTrace();
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? synchronized (B) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? System.out.println("1");
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? });
? ? ? ? ? ? Thread t2 = new Thread(new Runnable() {
? ? ? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? ? ? publicvoid run() {
? ? ? ? ? ? ? ? ? ? ? ? ? ? synchronized (B) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? synchronized (A) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? System.out.println("2");
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? });
? ? ? ? ? ? t1.start();
? ? ? ? ? ? t2.start();
? ? }
}
這段代碼只是演示死鎖的場(chǎng)景,在現(xiàn)實(shí)中你可能不會(huì)寫(xiě)出這樣的代碼届吁。但是错妖,在一些更為復(fù)雜的場(chǎng)景中绿鸣,你可能會(huì)遇到這樣的問(wèn)題,比如t1拿到鎖之后暂氯,因?yàn)橐恍┊惓G闆r沒(méi)有釋放鎖(死循環(huán))潮模。又或者是t1拿到一個(gè)數(shù)據(jù)庫(kù)鎖,釋放鎖的時(shí)候拋出了異常株旷,沒(méi)釋放掉再登。
一旦出現(xiàn)死鎖,業(yè)務(wù)是可感知的晾剖,因?yàn)椴荒芾^續(xù)提供服務(wù)了锉矢,那么只能通過(guò)dump線程查看到底是哪個(gè)線程出現(xiàn)了問(wèn)題,以下線程信息告訴我們是DeadLockDemo類(lèi)的第42行和第31行引起的死鎖齿尽。
"Thread-2" prio=5 tid=7fc0458d1000 nid=0x116c1c000 waiting for monitor entry [116c1b000]
? ? java.lang.Thread.State: BLOCKED (on object monitor)
? ? ? ? at com.ifeve.book.forkjoin.DeadLockDemo$2.run(DeadLockDemo.java:42)
? ? ? ? - waiting to lock <7fb2f3ec0> (a java.lang.String)
? ? ? ? - locked <7fb2f3ef8> (a java.lang.String)
? ? ? ? at java.lang.Thread.run(Thread.java:695)
"Thread-1" prio=5 tid=7fc0430f6800 nid=0x116b19000 waiting for monitor entry [116b18000]
? ? java.lang.Thread.State: BLOCKED (on object monitor)
? ? ? ? at com.ifeve.book.forkjoin.DeadLockDemo$1.run(DeadLockDemo.java:31)
? ? ? ? - waiting to lock <7fb2f3ef8> (a java.lang.String)
? ? ? ? - locked <7fb2f3ec0> (a java.lang.String)
? ? ? ? at java.lang.Thread.run(Thread.java:695)
現(xiàn)在我們介紹避免死鎖的幾個(gè)常見(jiàn)方法沽损。
·避免一個(gè)線程同時(shí)獲取多個(gè)鎖。
·避免一個(gè)線程在鎖內(nèi)同時(shí)占用多個(gè)資源循头,盡量保證每個(gè)鎖只占用一個(gè)資源绵估。
·嘗試使用定時(shí)鎖,使用lock.tryLock(timeout)來(lái)替代使用內(nèi)部鎖機(jī)制卡骂。
·對(duì)于數(shù)據(jù)庫(kù)鎖国裳,加鎖和解鎖必須在一個(gè)數(shù)據(jù)庫(kù)連接里,否則會(huì)出現(xiàn)解鎖失敗的情況全跨。
資源限制的挑戰(zhàn)
(1)什么是資源限制
資源限制是指在進(jìn)行并發(fā)編程時(shí)缝左,程序的執(zhí)行速度受限于計(jì)算機(jī)硬件資源或軟件資源。例如浓若,服務(wù)器的帶寬只有2Mb/s渺杉,某個(gè)資源的下載速度是1Mb/s每秒,系統(tǒng)啟動(dòng)10個(gè)線程下載資源挪钓,下載速度不會(huì)變成10Mb/s是越,所以在進(jìn)行并發(fā)編程時(shí),要考慮這些資源的限制碌上。硬件資源限制有帶寬的上傳/下載速度倚评、硬盤(pán)讀寫(xiě)速度和CPU的處理速度。軟件資源限制有數(shù)據(jù)庫(kù)的連接數(shù)和socket連接數(shù)等馏予。
(2)資源限制引發(fā)的問(wèn)題
在并發(fā)編程中蔓纠,將代碼執(zhí)行速度加快的原則是將代碼中串行執(zhí)行的部分變成并發(fā)執(zhí)行,但是如果將某段串行的代碼并發(fā)執(zhí)行吗蚌,因?yàn)槭芟抻谫Y源腿倚,仍然在串行執(zhí)行,這時(shí)候程序不僅不會(huì)加快執(zhí)行蚯妇,反而會(huì)更慢敷燎,因?yàn)樵黾恿松舷挛那袚Q和資源調(diào)度的時(shí)間暂筝。例如,之前看到一段程序使用多線程在辦公網(wǎng)并發(fā)地下載和處理數(shù)據(jù)時(shí)硬贯,導(dǎo)致CPU利用率達(dá)到100%焕襟,幾個(gè)小時(shí)都不能運(yùn)行完成任務(wù),后來(lái)修改成單線程饭豹,一個(gè)小時(shí)就執(zhí)行完成了鸵赖。
(3)如何解決資源限制的問(wèn)題
對(duì)于硬件資源限制,可以考慮使用集群并行執(zhí)行程序拄衰。既然單機(jī)的資源有限制它褪,那么就讓程序在多機(jī)上運(yùn)行。比如使用ODPS翘悉、Hadoop或者自己搭建服務(wù)器集群茫打,不同的機(jī)器處理不同的數(shù)據(jù)⊙欤可以通過(guò)“數(shù)據(jù)ID%機(jī)器數(shù)”老赤,計(jì)算得到一個(gè)機(jī)器編號(hào),然后由對(duì)應(yīng)編號(hào)的機(jī)器處理這筆數(shù)據(jù)制市。
對(duì)于軟件資源限制抬旺,可以考慮使用資源池將資源復(fù)用随闺。比如使用連接池將數(shù)據(jù)庫(kù)和Socket連接復(fù)用坞生,或者在調(diào)用對(duì)方webservice接口獲取數(shù)據(jù)時(shí)澳腹,只建立一個(gè)連接磺送。
(4)在資源限制情況下進(jìn)行并發(fā)編程
如何在資源限制的情況下,讓程序執(zhí)行得更快呢烛谊?方法就是,根據(jù)不同的資源限制調(diào)整程序的并發(fā)度,比如下載文件程序依賴(lài)于兩個(gè)資源——帶寬和硬盤(pán)讀寫(xiě)速度振坚。有數(shù)據(jù)庫(kù)操作時(shí),涉及數(shù)據(jù)庫(kù)連接數(shù)斋扰,如果SQL語(yǔ)句執(zhí)行非扯砂耍快,而線程的數(shù)量比數(shù)據(jù)庫(kù)連接數(shù)大很多传货,則某些線程會(huì)被阻塞屎鳍,等待數(shù)據(jù)庫(kù)連接。