十三、Java線程基礎

本篇介紹線程的基礎知識,包括:線程是什麼、線程爲什麼有用處、怎樣開始編寫使用線程的程序、如何控制線程、如何在線程之間交換數據以及線程如何互相通信。

一、線程是什麼

       進程是在某種程度上相互隔離的、獨立運行的程序。線程也稱作輕量級進程,就像進程一樣,線程在程序中是獨立的、併發的執行,每個線程有自己的堆棧、程序計數器和局部變量。但是與進程想比,進程中的線程之間的隔離程度要小,線程共享內存、文件句柄和其他每個進程應有的狀態。進程可以支持多個線程,這多個線程看似是同時執行,但相互之間並不同步。一個進程中的多個線程共享相同的內存地址空間,這就意味着一個進程中的多個線程可以訪問相同的變量和對象,而且他們從同一堆中分配對象。儘管這讓線程之間共享數據變得容易,但要注意確保它們不會干擾同一進程裏的其他線程。

      每個Java程序都至少有一個線程--主線程。當一個java程序啓動時,jvm會創建主線程,並在改線程中調用程序的main方法。JVM還創建了其他線程,如垃圾收集、對象終止和其他JVM內務處理任務相關的線程。其他工具也創建線程,如servlet容器、RMI、應用程序服務器等。

 

二、線程爲什麼有用處

        使用線程的好處如下:可以更高效利用多處理器系統、執行異步或後臺處理、簡化建模等。

       (1) 利用多處理器系統:服務器系統甚至臺式機系統都可能有多個處理器,可以利用多個處理器,並調度線程在任何可用的處理器上執行。調度的基本單位通常是線程。如果某個程序只有一個活動的線程,則一次只能在一個處理器上運行。如果某個程序有多個活動線程,那麼可以同時調度多個線程。在設計良好的程序中,使用多個線程可以有效提高程序吞吐量和性能。

        (2)異步或後臺處理:舉個例子,服務器應用程序從遠程來源(如Socket套接字)獲取輸入。當讀取套接字時,如果當前沒有可用數據,那麼對SocketInputStream.read()的調用將會阻塞,直到有可用數據爲止。

      第一種方法:單線程程序要讀取套接字,而套接字另一端的實體並未發送任何數據,那麼程序就永遠等待而不執行其他操作。

      第二種方法:輪詢套接字檢查是否有可用數據。但通常不使用這種做法,因爲影響性能。

      第三種方法:創建一個線程來讀取套接字,那麼當這個線程等待套接字中的輸入時,主線程就可以執行其他任務。甚至可以創建多個線程來同時讀取多個套接字。當有可用數據時,通過喚醒正在等待的線程,線程就得到了通知,而不必輪詢檢查是否有可用數據。

     (3)簡化建模

      在某些場景下使用線程可以使程序編寫和維護起來更簡單。舉2個例子。一個仿真應用程序,要模擬多個實體之間的交互作用。給每個實體一個自己的線程可以使建模簡化。

第二個例子是使用單獨線程來簡化程序的實例。在一個應用程序有多個獨立的事件驅動的組件時,例如一個應用程序可能有這樣一個組件,該組件在某個事件之後用秒數倒計時,並更新屏幕顯示。與其讓一個主循環定期檢查時間並更新顯示,不如讓一個線程什麼也不做,一直休眠直到某事件發生後,更新屏幕上的計數器。這樣程序就根本無需擔心計數器。

示例:使用一個線程用於計時,並使用另一個線程完成工作。

 

三、線程API

Object類定義了wait(),notify(),notifyAll()方法,必須擁有相關對象的鎖。這些方法是更復雜的鎖定、排隊和併發性代碼的構建。但與其使用wait()和notify()來編寫調度程序、線程池、隊列和鎖,不如使用上面介紹的java.util.concurrent包中的方法。

wait():會讓調用線程休眠,直到用Thread.interrupt()中斷它、過了指定時間、或者另一個線程用notify()或notifyAll()喚醒它。

notify():當對某個對象調用notify()時,如果有任何線程正在通過wait()等待該對象,那麼就會喚醒其中一個線程。當對某個對象調用notifyAll()時,會喚醒所有正在等待該對象的線程。

 

 

 

     

發佈了42 篇原創文章 · 獲贊 0 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章