線程的同步是Java多線程編程的難點,往往開發(fā)者搞不清楚什么是競爭資源、什么時候需要考慮同步,怎么同步等等問題,當(dāng)然,這些問題沒有很明確的答案,但有些原則問題需要考慮,是否有競爭資源被同時改動的問題?對于同步,在具體的Java代碼中需要完成以下兩個操作:把競爭訪問的資源標(biāo)識為private;同步哪些修改變量的代碼,使用synchronized關(guān)鍵字同步方法或代碼。當(dāng)然這不是唯一控制并發(fā)安全的途徑。synchronized關(guān)鍵字使用說明synchronized只能標(biāo)記非抽象的方法,不能標(biāo)識成員變量。為了演示同步方法的使用,構(gòu)建了一個信用卡賬戶,起初信用額為100w,然后模擬透支、存款等多個操作。
顯然銀行賬戶User對象是個競爭資源,而多個并發(fā)操作的是賬戶方法oper(int x),當(dāng)然應(yīng)該在此方法上加上同步,并將賬戶的余額設(shè)為私有變量,禁止直接訪問。工作原理線程是進程中的實體,一個進程可以擁有多個線程,一個線程必須有一個父進程。線程不擁有系統(tǒng)資源,只有運行必須的一些數(shù)據(jù)結(jié)構(gòu);它與父進程的其它線程共享該進程所擁有的全部資源。線程可以創(chuàng)建和撤消線程,從而實現(xiàn)程序的并發(fā)執(zhí)行。
一般,線程具有就緒、阻塞和運行三種基本狀態(tài)。在多中央處理器的系統(tǒng)里,不同線程可以同時在不同的中央處理器上運行,甚至當(dāng)它們屬于同一個進程時也是如此。大多數(shù)支持多處理器的操作系統(tǒng)都提供編程接口來讓進程可以控制自己的線程與各處理器之間的關(guān)聯(lián)度(affinity)。有時候,線程也稱作輕量級進程。就象進程一樣,線程在程序中是獨立的、并發(fā)的執(zhí)行路徑,每個線程有它自己的堆棧、自己的程序計數(shù)器和自己的局部變量。但是,與分隔的進程相比,進程中的線程之間的隔離程度要小。它們共享內(nèi)存、文件句柄和其它每個進程應(yīng)有的狀態(tài)。進程可以支持多個線程,它們看似同時執(zhí)行,但互相之間并不同步。一個進程中的多個線程共享相同的內(nèi)存地址空間,這就意味著它們可以訪問相同的變量和對象,而且它們從同一堆中分配對象。
盡管這讓線程之間共享信息變得更容易,但您必須小心,確保它們不會妨礙同一進程里的其它線程。Java 線程工具和 API看似簡單。但是,編寫有效使用線程的復(fù)雜程序并不十分容易。因為有多個線程共存在相同的內(nèi)存空間中并共享相同的變量,所以您必須小心,確保您的線程不會互相干擾。線程屬性為了正確有效地使用線程,必須理解線程的各個方面并了解Java 實時系統(tǒng)。必須知道如何提供線程體、線程的生命周期、實時系統(tǒng)如 何調(diào)度線程、線程組、什么是幽靈線程(Demo nThread)。線程體所有的操作都發(fā)生在線程體中,在Java中線程體是從Thread類繼承的run()方法,或?qū)崿F(xiàn)Runnable接口的類中的run()方法。當(dāng)線程產(chǎn)生并初始化后,實時系統(tǒng)調(diào)用它的run()方法。run()方法內(nèi)的代碼實現(xiàn)所產(chǎn)生線程的行為,它是線程的主要部分。
雖然我們說線程是并發(fā)運行的。然而事實常常并非如此。正如前面談到的,當(dāng)系統(tǒng)中只有一個CPU時,以某種順序在單CPU情況下執(zhí)行多線程被稱為調(diào)度(scheduling)。Java采用的是一種簡單、固定的調(diào)度法,即固定優(yōu)先級調(diào)度。這種算法是根據(jù)處于可運行態(tài)線程的相對優(yōu)先級來實行調(diào)度。當(dāng)線程產(chǎn)生時,它繼承原線程的優(yōu)先級。在需要時可對優(yōu)先級進行修改。在任何時刻,如果有多條線程等待運行,系統(tǒng)選擇優(yōu)先級最高的可運行線程運行。只有當(dāng)它停止、自動放棄、或由于某種原因成為非運行態(tài)低優(yōu)先級的線程才能運行。如果兩個線程具有相同的優(yōu)先級,它們將被交替地運行?!ava實時系統(tǒng)的線程調(diào)度算法還是強制性的,在任何時刻,如果一個比其他線程優(yōu)先級都高的線程的狀態(tài)變?yōu)榭蛇\行態(tài),實時系統(tǒng)將選擇該線程來運行。一個應(yīng)用程序可以通過使用線程中的方法setPriority(int),來設(shè)置線程的優(yōu)先級大小。