Java線程同步與多線程

 

20120408

交通燈、銀行項目都涉及到了多線程。先搞懂線程裏大概的知識點吧。
一、進程與線程
首先就是進程與線程的區別。我們在操作系統中運行一個程序,都會在系統建立一個進程(任務管理器的exe),而在這個進程中,就至少有一個線程在運行,它叫做主線程,也是這個程序運行的入口點,感覺就像一個java工程的含有main主程序(入口點)的那個java程序一樣。線程也是程序運行時的基本執行單元。在操作系統中可以有多個進程,包括系統進程和用戶進程,一個進程中又可以有一個或多個線程。進程和進程之間不共享內存,都是在各自獨立的內存空間中運行,內存獨佔吧。但一個進程中的線程可以共享系統分配給這個進程的內存空間。線程不僅可以共享進程的內存,而且還擁有一個屬於自己的內存空間,這段內存空間也叫做線程棧, 是在建立線程時由系統分配的,主要用來保存線程內部所使用的數據,如線程執行函數中所定義的變量。

在操作系統將進程分成多個線程後,這些線程可以再操作系統的管理下併發執行,從而大大提高了程序的運行效率。但一塊CPU同時只能執行一條指令,所以操作系統實際上是在執行多個線程的過程中,在一個線程空閒時將其撤下,並去執行另一個線程。這叫做線程調度。只不過互相切換的時間短(幾毫秒級),所以看上去像是多個線程在同時執行。

二、java線程的同步與異步、線程池

1、多線程併發執行時,有可能同時請求同一個資源,所以有可能線程A修改了B線程的數據,而B線程又修改了A線程的數據,這樣會造成數據的不安全。這又是由於全局資源造成的,有時爲了解決這個問題,優先考慮使用局部變量,使用同步代碼塊,出於這樣的安全考慮就必須犧牲系統處理性能,加在多線程併發時資源掙奪最激烈的地方,這就實現了線程的同步機制。
同步:A線程要請求某個資源,但是此資源正在被B線程使用中,因爲同步機制存在,A線程請求不到,怎麼辦,A線程只能等待下去
異步:A線程要請求某個資源,但是此資源正在被B線程使用中,因爲沒有同步機制存在,A線程仍然請求的到,A線程無需等待。

顯然,同步是最安全,最保險的。而異步不安全,容易導致死鎖,這樣一個線程死掉就會導致整個進程崩潰,但沒有同步機制的存在,性能會有所提升。

說白了就是當多個線程同時訪問同一個資源的時候,爲了保證數據的安全,避免讀髒數據,就要給對這個資源的訪問加鎖,就是synchronized(互斥),即同時只能有一個線程去訪問數據,當訪問完畢後解鎖,其他線程才能去訪問。用張孝祥老師的話講就是,當兩個線程同時訪問一個相同的數據,會出問題,所以要實現互斥,就是加上synchronized。synchronized用於多線程設計,有了synchronized關鍵字,多線程程序的運行結果將變得可以控制。synchronized關鍵字用於保護共享數據,它依靠"鎖"機制進行多線程同步,"鎖"有2種,一種是對象鎖,一種是類鎖。
它可以修飾的對象有:
1)synchronized{static方法 or 普通方法} 函數的修飾符, 就是同步方法.
2)synchronized{修飾代碼塊} 可作爲函數內語句的修飾符, 就是同步語句塊
3)synchronized{對象引用} 注意對象必須是線程安全的.(比如: StringBuffer在JDK1.5中是線程安全的, 而數組, ArrayList是不安全的)

三、交通燈、銀行項目裏都用到的Executors類的方法創建線程池

Executors類提供了一系列工廠方法用於創先線程池,返回的線程池都實現了ExecutorService接口。
1)newFixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads);
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory);

創建一個可重用固定線程集合的線程池,以共享的無界隊列方式來運行這些線程。如果在關閉前的執行期間由於失敗而導致任何線程終止,那麼一個新線程將代替它執行後續的任務(如果需要)。
2)newSingleThreadExecutor
public static ExecutorService newSingleThreadExecutor();
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory);

創建一個使用單個 worker 線程的 Executor,以無界隊列方式來運行該線程。(注意,如果因爲在關閉前的執行期間出現失敗而終止了此單個線程,那麼如果需要,一個新線程將代替它執行後續的任務)。可保證順序地執行各個任務,並且在任意給定的時間不會有多個線程是活動的。與其他等效的 newFixedThreadPool(1) 不同,可保證無需重新配置此方法所返回的執行程序即可使用其他的線程。
3)newCachedThreadPool
public static ExecutorService newCachedThreadPool();
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory);

創建一個可根據需要創建新線程的線程池,但是在以前構造的線程可用時將重用它們。對於執行很多短期異步任務的程序而言,這些線程池通常可提高程序性能。調用 execute 將重用以前構造的線程(如果線程可用)。如果現有線程沒有可用的,則創建一個新線程並添加到池中。終止並從緩存中移除那些已有 60 秒鐘未被使用的線程。因此,長時間保持空閒的線程池不會使用任何資源。注意,可以使用 ThreadPoolExecutor 構造方法創建具有類似屬性但細節不同(例如超時參數)的線程池。
4)newScheduledThreadPool
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize);
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory);

創建一個線程池,它可安排在給定延遲後運行命令或者定期地執行,就像張孝祥老師所說的“定時炸彈”!!
5)newSingleThreadScheduledExecutor
public static ScheduledExecutorService newSingleThreadScheduledExecutor();
public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory);

創建一個單線程執行程序,它可安排在給定延遲後運行命令或者定期地執行。(注意,如果因爲在關閉前的執行期間出現失敗而終止了此單個線程,那麼如果需要,一個新線程會代替它執行後續的任務)。可保證順序地執行各個任務,並且在任意給定的時間不會有多個線程是活動的。與其他等效的 newScheduledThreadPool(1) 不同,可保證無需重新配置此方法所返回的執行程序即可使用其他的線程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章