首先,要辨析進程與線程的概念: java
進程是程序執行的過程,它持有資源和線程,相對於程序自己而言具備動態性。 多線程
線程是系統中最小的執行單元,同一個進程中可能有多個線程,它們共享該進程持有的資源。線程的通訊也稱爲線程的交互,方式主要有互斥和同步。同步是指線程之間經過共同協做完成某項工做,線程間具備次序性;互斥是指線程間對某一資源的競爭,一次只能有一個線程訪問該資源。 spa
介紹完了這些基本概念,下面簡單介紹一下Java對多線程的支持. 線程
java中經過類Thread和接口Runnable來實現多線程的操做。它們都有一個run方法來指定線程工做時執行的代碼。對象
Thread類的經常使用方法blog
類別繼承 |
名稱接口 |
簡介生命週期 |
線程的建立隊列 |
Thread() |
|
Thread(String name) |
||
Thread(Runnable target) |
||
Thread(Runnable target, String name) |
||
線程的方法 |
void start() |
啓動線程 |
static void sleep(long millis) |
線程休眠 |
|
static void sleep(long millis, int nanos) |
||
void join() |
某線程調用join方法後,使其餘線程等待該線程終止 |
|
void join(long millis) |
||
void join(long millis, int nanos) |
||
static void yield() |
當前正在運行的線程馬上釋放處理器,從新加入競爭處理器的隊列 |
|
獲取線程引用 |
static Thread currentThread() |
返回當前正在運行的線程的引用 |
使用多線程有兩種方式,一種是直接繼承Thread類,一種是實現Runnable接口
另外,經過volatile關鍵字聲明的成員變量能夠保證當其餘線程修改該成員變量後,本線程能夠正確讀取到此成員變量的值。
請結合OS中進程的5態來思考。如下線程狀態和方法的介紹來自DreamSea(張小哲)
Ø線程的方法(Method)、屬性(Property)
每一個類都有本身的優先級,通常property用1-10的整數表示,默認優先級是5,優先級最高是10;優先級高的線程並不必定比優先級低的線程執行的機會高,只是執行的機率高;默認一個線程的優先級和建立他的線程優先級相同;
2)Thread.sleep()/sleep(long millis)
當前線程睡眠/millis的時間(millis指定睡眠時間是其最小的不執行時間,由於sleep(millis)休眠到達後,沒法保證會被JVM當即調度);sleep()是一個靜態方法(static method) ,因此他不會中止其餘的線程也處於休眠狀態;線程sleep()時不會失去擁有的對象鎖。 做用:保持對象鎖,讓出CPU,調用目的是不讓當前線程獨自霸佔該進程所獲取的CPU資源,以留必定的時間給其餘線程執行的機會;
讓出CPU的使用權,給其餘線程執行機會、讓同等優先權的線程運行(但並不保證當前線程會被JVM再次調度、使該線程從新進入Running狀態),若是沒有同等優先權的線程,那麼yield()方法將不會起做用。
5)object.wait() 當一個線程執行到wait()方法時,他就進入到一個和該對象相關的等待池(Waiting Pool)中,同時失去了對象的機鎖—暫時的,wait後還要返還對象鎖。當前線程必須擁有當前對象的鎖,若是當前線程不是此鎖的擁有者,會拋出IllegalMonitorStateException異常,因此wait()必須在synchronized block中調用。sleep()和wait()方法的最大區別是:sleep()睡眠時,保持對象鎖,仍然佔有該鎖;而wait()睡眠時,釋放對象鎖。可是wait()和sleep()均可以經過interrupt()方法打斷線程的暫停狀態,從而使線程馬上拋出InterruptedException(但不建議使用該方法)。
喚醒在當前對象等待池中等待的第一個線程/全部線程。notify()/notifyAll()也必須擁有相同對象鎖,不然也會拋出IllegalMonitorStateException異常。
非正確中止的方法:stop()
要正確中止線程,應該使用正確的退出標記。正常狀況下run方法執行完畢線程就中止了,可是有些狀況下run方法中須要while循環保持輪詢,因此應該爲while循環設置合適的退出條件,即退出標記,保證線程正確中止。
或者使用interrupt()方法的初衷並非要中止線程,正常狀況下,調用該方法能夠將中斷標記設置爲TRUE。可是,當某個線程由於調用了wait()或者sleep()等方法而被阻塞時,此時調用interrupt()方法並不能正確的將interrupted標記設置爲TRUE,而且同時會拋出中斷異常。
爭用條件:當多個線程同時共享訪問同一個內存數據時,每一個線程都嘗試操做該數據,從而致使數據被破壞。
互斥是指在同一時刻只有一個線程能夠對臨界區進行操做。在JAVA中,能夠經過synchronized塊或者方法來實現。
在synchronized塊中,須要對某個對象進行加鎖,並將須要互斥的代碼放入synchronized塊中,從而來實現互斥行爲。得到該鎖的進程能夠進入該synchronized塊中.
而同步則是線程之間的一種通訊機制,經過同步能夠規定線程執行的順序。例如,當線程不知足訪問某資源時,能夠經過調用鎖對象的lock.wait()方法,使該線程讓出CPU,讓出鎖,並在該鎖對象的waitset中等待。知足條件時,能夠經過lock.notify()方法隨機喚醒一條線程,lock.notifyAll()則喚醒該waitset中全部的線程,使它們從新競爭該鎖。被喚醒的線程從wait()方法處繼續執行。