摘 要:本文分析并描述了Java多線程訪問控制的基本方法和多線程同步訪問的控制方法,以及使用優(yōu)先級(jí)解決死鎖問題的方法,并且用簡(jiǎn)單語句作說明。
關(guān)鍵詞:Java;多線程;同步控制
中圖分類號(hào):TP312
1 Java多線程的基本控制
在Java中,一個(gè)線程從創(chuàng)建到死亡稱為線程的一個(gè)生命周期,它的生命周期有多個(gè)不同狀態(tài),一般為:Enabled、Running、Sleeping、Joining、Waiting、Locking。對(duì)于線程的這些狀態(tài),Java在Thread類中定義了一些方法可以在程序中手動(dòng)控制。要結(jié)束一個(gè)線程的運(yùn)行,可以使用stop()方法。但是stop()方法并不是非常安全的,它會(huì)強(qiáng)制中止一個(gè)線程的運(yùn)行,但是會(huì)釋放這個(gè)線程鎖住的所有對(duì)象,這些對(duì)象被解鎖后就可能被其他的線程直接訪問,導(dǎo)致錯(cuò)誤的結(jié)果。因此,要中止一個(gè)線程,最好是設(shè)置一個(gè)標(biāo)志位,在run()方法中根據(jù)這個(gè)標(biāo)記來判斷是否繼續(xù)保持狀態(tài)。要中止線程的時(shí)候,可以使用setRunFlag()方法。
在暫停和恢復(fù)線程執(zhí)行時(shí)也會(huì)出現(xiàn)同樣的問題??梢允褂肨hread類中supspend()和resume()方法來暫停和恢復(fù),但不建議使用,它們?nèi)菀自斐删€程的死鎖。解決的方法也是使用一定的標(biāo)志變量。使用setsuspendFlag(true)可以暫停線程的執(zhí)行,暫停時(shí)間的指定是通過sleep()方法來實(shí)現(xiàn),暫停結(jié)束就回到等待隊(duì)列,不是恢復(fù)執(zhí)行狀態(tài)。所以sleep()方法不能精確控制線程計(jì)劃工作的時(shí)間尺度。
下面用模擬一個(gè)龜兔接力跑的實(shí)例來演示Java多線程的sleep()方法的控制。模擬的接力跑中有一只烏龜和一只兔子。當(dāng)兔子跑完400米將接力棒交給烏龜,烏龜跑完400米后結(jié)束。部分代碼如下:
2 Java多線程的同步控制
多線程程序中,多個(gè)線程可以共享相同資源,這可能導(dǎo)致沖突。Java使用同步機(jī)制來解決這個(gè)問題。這個(gè)同步機(jī)制使用synchronized關(guān)鍵字,它主要用于多線程共享數(shù)據(jù)的同步,使用加鎖的機(jī)制,控制變量或代碼塊在某個(gè)時(shí)間段只能被一個(gè)線程訪問。
Java中synchronized既可作為方法的修飾符,鎖住方法,也可在方法內(nèi)部鎖住部分語句。Synchronized方法和synchronized代碼塊在使用時(shí)是有區(qū)別的。將訪問共享數(shù)據(jù)的方法加上synchronized,例如把synchronized當(dāng)作方法修飾符:
Public synchronized void m1(){……}
這就是同步方法。當(dāng)某個(gè)線程調(diào)用這個(gè)同步方法時(shí),會(huì)開始執(zhí)行直到完畢為止,其它想要調(diào)用這個(gè)方法的線程會(huì)進(jìn)入阻塞狀態(tài),一直到這個(gè)方法獲得釋放為止。使用synchronized來修飾一個(gè)比較大的方法時(shí),也會(huì)鎖住其它一些不需要鎖住的數(shù)據(jù),導(dǎo)致程序效率下降。Synchronized塊則是把方法內(nèi)的某段代碼使用synchronized來修飾,可以減少同步范圍。例如:Public void m1(){ …… Synchronized(so){ …… }}
使用synchronized修飾時(shí),就代表著同步機(jī)制啟動(dòng),某個(gè)時(shí)刻只能某個(gè)線程訪問數(shù)據(jù)和資源,阻止其它線程訪問,這種狀態(tài)即使出現(xiàn)阻塞和死鎖現(xiàn)象也不會(huì)解除。
3 Java多線程的死鎖問題
為了控制資源的訪問沖突,需要使用synchronized對(duì)訪問資源進(jìn)行加鎖,但加鎖會(huì)帶來一個(gè)潛在的危險(xiǎn):死鎖。如果兩個(gè)或兩個(gè)以上的線程在等待兩個(gè)或兩個(gè)以上的鎖被釋放,但實(shí)際上這些鎖根本就不會(huì)被解鎖,那么這些線程就會(huì)進(jìn)入無限等待的狀態(tài),稱之為死鎖。線程等待解鎖的這種狀態(tài)有時(shí)也被稱作堵塞。死鎖例子部分代碼如下:
4 Java多線程的優(yōu)先級(jí)
在多線程編程中要預(yù)防死鎖的發(fā)生,不然死鎖后會(huì)導(dǎo)致浪費(fèi)大量時(shí)間和資源。防止死鎖的方法很多,最重要的就是防止循環(huán)等待的發(fā)生??梢允褂迷O(shè)置線程的優(yōu)先級(jí)來解決這一問題。同一時(shí)刻會(huì)有很多在排隊(duì)等待資源的線程,它們各自的重要性是不同的。可以賦予每個(gè)線程不同的優(yōu)先級(jí),讓任務(wù)更急的線程獲得更高的優(yōu)先級(jí),更快的進(jìn)入執(zhí)行狀態(tài)。
Java中提供了10個(gè)等級(jí)的線程優(yōu)先級(jí),最低為1,最高為10,默認(rèn)優(yōu)先級(jí)為5。對(duì)于一個(gè)新創(chuàng)建的線程,如果沒有指定優(yōu)先級(jí),它的優(yōu)先級(jí)將和它的父線程優(yōu)先級(jí)一致。使用setPriority()方法可以為線程指定優(yōu)先級(jí)。
例如:int newPrio=Thread.currentThread( ).getPriority( )+1;
Thread.currentThread( ).setPriority(newPrio);
5 結(jié)束語
Java多線程編程可以合理的調(diào)用多項(xiàng)任務(wù),功能非常強(qiáng)大。但是多線程共享數(shù)據(jù)或資源時(shí)會(huì)導(dǎo)致執(zhí)行的錯(cuò)誤,因此多線程訪問控制管理機(jī)制在解決數(shù)據(jù)不一致性、資源沖突等問題時(shí)是非常有用的。高質(zhì)量的使用Java多線程訪問控制管理機(jī)制可以提高程序運(yùn)行效率,縮短任務(wù)執(zhí)行的時(shí)間。
參考文獻(xiàn):
[1]明日科技.Java從入門到精通(3版)[M].北京:清華大學(xué)出版社,2013.
[2]路勇.Java多線程同步問題分析[J].軟件,2012(04):31-33.
作者簡(jiǎn)介:梁德華(1977-),男,江西瑞昌人,華中科技大學(xué)軟件工程碩士,講師,研究方向:軟件工程、軟件技術(shù)教學(xué)。
作者單位:江西旅游商貿(mào)職業(yè)學(xué)院 藝術(shù)傳媒與計(jì)算機(jī)分院,南昌 330100