在java 的api 中, 提供了 Thread類 和Runnable 接口 來實現相應的多線程功能。java
所以呢 要開多線程,有兩種方式
編程
Main Thread { () { System..println(Thread.().getId()+Thread.().getName())} (String[] arg){ i = (i<){ i++Main main = Main()main.start()} } }
提供runable,主要是解決 多繼承的問題,最終仍是從Thread 這個類的start方法 升成一條新線程api
Main2 Runnable { () { System..println(Thread.().getId()+Thread.().getName())} (String[] arg){ i = (i<){ i++Thread thread = Thread(Main2())thread.()} } }
新建: 這個比較好理解,當新建一個Thread 對象實例的時候,此時 這個Thread對象處在 new 狀態安全
就緒: 當調用 Thread類的start 方法,則表示 改Thread類已經準備就行 等待分配CPU資源多線程
須要注意的是,start方法並不是就是開始運行一個線程,它是把線程對象放到就緒隊列等待分配CPU時間片。併發
另外 CPU的調度也並不是是按照進入隊列前後決定了,由多方面的因素和分配策略所決定了,不受人爲控制,這也是併發編程難以debug的緣由之一。
編輯器
運行:這個也比較好理解,就是thread對象已經獲得CPU時間片 而且開始運行了。spa
死亡: 這個狀態表示 改線程已經完成了或者強制中斷(人爲或者拋出異常)須要注意的是,死亡狀態下的線程不能復生,如再調用start 方法 會拋出java.lang.IllegalThreadStateException 的異常。線程
阻塞:這個狀態是指運行到一半的線程因爲某些因素 如 等待 I/O 資源或者人爲 阻塞(sleep 方法)時 ,會進入阻塞狀態,當阻塞條件消失瞭如 等待的I/O資源就緒了或者 人爲設定的阻塞時間已過,這個線程會從新回到就緒狀態,等待CPU調度。debug
狀態切換多發生在處於運行狀態的線程,由於它最爲複雜,它能夠變爲阻塞狀態、就緒狀態和死亡狀態。
處於就緒狀態的線程,若是得到了cpu的調度,就會從就緒狀態變爲運行狀態,執行run()方法中的任務。
若是該線程失去了cpu資源,就會又從運 行狀態變爲就緒狀態。從新等待系統分配資源。也能夠對在運行狀態的線程調用yield()方法,它就會讓出cpu資源,再次變爲就緒狀態。
當發生以下狀況是,線程會從運行狀態變爲阻塞狀態:
①、線程調用sleep方法主動放棄所佔用的系統資源
②、線程調用一個阻塞式IO方法,在該方法返回以前,該線程被阻塞
③、線程試圖得到一個同步監視器,但更改同步監視器正被其餘線程所持有
④、線程在等待某個通知(notify)
⑤、程序調用了線程的suspend方法將線程掛起。不過該方法容易致使死鎖,因此程序應該儘可能避免使用該方法。
當線程的run()方法執行完,或者被強制性地終止,例如出現異常,或者調用了stop()、desyory()方法等等,就會從運行狀態轉變爲死亡狀態。
void |
destroy() 已過期。 該方法最初用於破壞該線程,但不做任何清除。它所保持的任何監視器都會保持鎖定狀態。不過,該方法決不會被實現。即便要實現,它也極有可能以 suspend() 方式被死鎖。若是目標線程被破壞時保持一個保護關鍵系統資源的鎖,則任何線程在任什麼時候候都沒法再次訪問該資源。若是另外一個線程曾試圖鎖定該資源,則會出現死鎖。這類死鎖一般會證實它們本身是「凍結」的進程。 |
void |
interrupt() 中斷線程。 |
void |
join() 等待該線程終止。 |
void |
join(long millis) 等待該線程終止的時間最長爲 millis 毫秒。 |
void |
join(long millis, int nanos) 等待該線程終止的時間最長爲 millis 毫秒 + nanos 納秒。 |
void |
resume() 已過期。 該方法只與 suspend() 一塊兒使用,但 suspend() 已經遭到反對,由於它具備死鎖傾向。 |
void |
setDaemon(boolean on) 將該線程標記爲守護線程或用戶線程。 |
void |
setPriority(int newPriority) 更改線程的優先級。 |
static void |
sleep(long millis) 在指定的毫秒數內讓當前正在執行的線程休眠(暫停執行),此操做受到系統計時器和調度程序精度和準確性的影響。 |
static void |
sleep(long millis, int nanos) 在指定的毫秒數加指定的納秒數內讓當前正在執行的線程休眠(暫停執行),此操做受到系統計時器和調度程序精度和準確性的影響。 |
void |
start() 使該線程開始執行;Java 虛擬機調用該線程的 run 方法。 |
void |
stop() 已過期。 該方法具備固有的不安全性。用 Thread.stop 來終止線程將釋放它已經鎖定的全部監視器(做爲沿堆棧向上傳播的未檢查 ThreadDeath 異常的一個天然後果)。若是之前受這些監視器保護的任何對象都處於一種不一致的狀態,則損壞的對象將對其餘線程可見,這有可能致使任意的行爲。stop 的許多使用都應由只修改某些變量以指示目標線程應該中止運行的代碼來取代。目標線程應按期檢查該變量,而且若是該變量指示它要中止運行,則從其運行方法依次返回。若是目標線程等待很長時間(例如基於一個條件變量),則應使用interrupt 方法來中斷該等待。 |
void |
stop(Throwable obj) 已過期。 該方法具備固有的不安全性。 |
void |
suspend() 已過期。 該方法已經遭到反對,由於它具備固有的死鎖傾向。若是目標線程掛起時在保護關鍵系統資源的監視器上保持有鎖,則在目標線程從新開始之前任何線程都不能訪問該資源。若是從新開始目標線程的線程想在調用 resume 以前鎖定該監視器,則會發生死鎖。這類死鎖一般會證實本身是「凍結」的進程。 |
static void |
yield() 暫停當前正在執行的線程對象,並執行其餘線程。 |
若是咱們須要讓當前正在執行的線程暫停一段時間,並進入阻塞狀態,則能夠經過調用Thread的sleep方法。
須要注意的是,睡眠的始終是當前正在運行的線程,而不是調用它的線程對象,它只對正在運行狀態的線程對象有效。
Sleep Thread { (String[] args) InterruptedException { System..println(Thread.().getName())Sleep myThread=Sleep()myThread.start()myThread.()Thread.()(i=i<i++){ System..println(+i)} } }
yield()方法和sleep()方法有點類似,它也是Thread類提供的一個靜態的方法,它也可讓當前正在執行的線程暫停,讓出cpu資源 給其餘的線程。可是和sleep()方法不一樣的是,它不會進入到阻塞狀態,而是進入到就緒狀態。yield()方法只是讓當前線程暫停一下,從新進入就緒 的線程池中,讓系統的線程調度器從新調度器從新調度一次,徹底可能出現這樣的狀況:當某個線程調用yield()方法以後,線程調度器又將其調度出來從新 進入到運行狀態執行。
實際上,當某個線程調用了yield()方法暫停以後,優先級與當前線程相同,或者優先級比當前線程更高的就緒狀態的線程更有可能得到執行的機會,固然,只是有可能,由於咱們不可能精確的干涉cpu調度線程。
Yield Thread { (){ i = (i<){ System..println(Thread.().getId()+Thread.().getName())Thread.()} } (String[] arg){ Yield yield1 = Yield()yield1.start()} }
TBD
TBD
使用setDaemon(true); 把線程置爲守護進程。在Daemon線程中產生的新線程也是Daemon的。
守護線程的用途:
守護線程一般用於執行一些後臺做業,例如在你的應用程序運行時播放背景音樂,在文字編輯器裏作自動語法檢查、自動保存等功能。Java的垃圾回收也是一個守護線程。守護線的好處就是你不須要關心它的結束問題。例如你在你的應用程序運行的時候但願播放背景音樂,若是將這個播放背景音樂的線程設定爲非守護線程,那麼在用戶請求退出的時候,
不只要退出主線程,還要通知播放背景音樂的線程退出;若是設定爲守護線程則不須要了
Daemon Thread { () { System..println(Thread.().getId()+Thread.().getName())} (String[] arg){ Daemon daemon = Daemon()daemon.setDaemon()daemon.start()} }
TBD