操做系統中的進程和線程的概念
操做系統中能夠同時執行多個任務,每一個任務就是進程;進程能夠同時執行多個任務,每一個任務就是線程。
線程的狀態
一、新建(new):線程對象被建立後就進入了新建狀態。如:Thread thread = new Thread();java
二、就緒狀態(Runnable):也被稱爲「可執行狀態」。線程對象被建立後,其餘線程調用了該對象的start()方法,從而啓動該線程。如:thread.start(); 處於就緒狀態的線程隨時可能被CPU調度執行。windows
三、運行狀態(Running):線程獲取CPU權限進行執行。須要注意的是,線程只能從就緒狀態進入到運行狀態。多線程
四、阻塞狀態(Blocked):阻塞狀態是線程由於某種緣由放棄CPU使用權限,暫時中止運行。直到線程進入就緒狀態,纔有機會進入運行狀態。阻塞的三種狀況:ide
1)等待阻塞:經過調用線程的wait()方法,讓線程等待某工做的完成。this
2)同步阻塞:線程在獲取synchronized同步鎖失敗(由於鎖被其餘線程佔用),它會進入同步阻塞狀態。spa
3)其餘阻塞:經過調用線程的sleep()或join()或發出了I/O請求時,線程會進入到阻塞狀態。當sleep()狀態超時、join()等待線程終止或超時、或者I/O處理完畢時,線程從新轉入就緒狀態。
操作系統
五、死亡狀態(Dead):線程執行完了或因異常退出了run()方法,該線程結束生命週期。線程
經常使用的實現多線程的方式
一、繼承Thread類3d
public class Thread implements Runnable {、、、、、}
由Thread的源碼能夠看出,Thread是實現了Runnable接口。code
二、實現Runnable接口
public interface Runnable { public abstract void run(); }
Runnable接口只有一個run()方法
————————————————————————————————————————————————
Thread和Runnable都是是實現實現多線程的方式。不一樣的是Thread是類,Runnable是接口——Thread自己實現了Runnable接口,一個類只能有一個父類,可是卻能夠是實現多個接口,所以Runnable具備更好的擴展性。
Thread實現多線程
public class MyThread extends Thread { private int i ; @Override/** 重寫run方法*/ public void run(){ for (int i = 0; i < 50 ; i++) { /** * 當繼承Thread類能夠直接用this獲取當前線程 * 用getName()獲取當前線程的名字 */ System.out.println(this.getName()+"-"+i); } } public static void main(String[] args) { for (int i = 0; i < 100 ; i++) { //經過Thread.currentThread()獲取當前線程 System.out.println(Thread.currentThread().getName()+" "+i); if(i==20){ //建立並啓動第一個線程 new MyThread().start(); //建立並啓動第二個線程 new MyThread().start(); } } } }
Runnable實現多線程
public class MyRunnable implements Runnable { private int i; @Override public void run() { for (int i = 0; i < 50; i++) { /**當線程類實現Runnable接口的時候,獲取當前線程只能用Thread.currentThread()*/ System.out.println(Thread.currentThread().getName()+" "+i); } } public static void main(String[] args) { for (int i = 0; i < 100; i++) { // System.out.println(Thread.currentThread().getName()+" "+i); if(i==20){ MyRunnable mr = new MyRunnable(); //經過new Start()方法建立新線程 new Thread(mr,"線程1").start(); new Thread(mr,"線程2").start(); } } } }
關於線程中的start()和run()
啓動線程使用start(),而不是run()!
在執行start()方法以前,只是有一個Thread對象,還沒一個真正的線程。(分配內存,初始化成員變量)
——>start()以後,線程狀態重新狀態到可執行狀態。(調用棧和計數器,線程沒運行,只是能夠運行)
——>當線程得到執行機會時,其目標run()方法將運行。
start():他的做用是啓動一個新線程,新線程會調用相應的run()方法。start()不能被重複調用。
run():和普通成員的方法同樣能夠被重複調用。單獨調用run()會在當前線程中執行run(),而不會啓動新的線程。
public class MyThread extends Thread { @Override/** 重寫run方法*/ public void run(){ } } MyThread myThread = new MyThread();
如:myThread.start()會啓動一個新的線程,而後在新線程中執行run()方法。
myThread.run()會直接在當前線程中運行run()方法,不會啓動一個線程。
start方法源碼:
public synchronized void start() { /** *若是線程不是就緒狀態就拋出異常 */ if (threadStatus != 0) throw new IllegalThreadStateException(); /* 將線程添加到group當中 */ group.add(this); boolean started = false; try { start0();//經過start0啓動線程 started = true;//設置started標記 } finally { try { if (!started) { group.threadStartFailed(this); } } catch (Throwable ignore) { /* do nothing. If start0 threw a Throwable then it will be passed up the call stack */ } } }
run方法源碼:
public void run() { if (target != null) { target.run(); } }
其中target是Runnable對象, 直接調用Thread線程中Runnable接口中run方法,不會新建一個線程。
當線程得到CPU,開始執行run()方法的線程執行體,則該線程處於運行狀態。
關於阻塞
進入阻塞的狀況: | 解除上面阻塞狀況: | |
一、線程調用sleep()方法主動釋放佔用的處理器資源 二、調用了一個阻塞式的IO方法,在方法返回前線程被阻塞 三、線程得到了一個同步監視器(Syschronized),但該監視器正被其餘線程持有 四、線程在等待某個通知(notify) 五、程序調用了線程的resume()方法將線程掛起。可是該方法容易發生死鎖,因此儘可能避免使用 |
一、調用sleep()方法通過了指定的時間 二、線程調用的IO阻塞方法已經返回 三、線程成功的得到了試圖取得的同步監視器 四、線程正在等待某個通知時,其餘線程發出了一個通知 五、處於掛起的線程被調用了resume()恢復方法。 |
線程從阻塞狀態只能進入就緒狀態,沒法進入運行狀態,而從就緒到運行不受程序控制,由系統線程調度決定。
得到資源進入運行狀態,失去資源進入就緒狀態。
線程死亡
線程死亡會以一下三種情況結束:
—>調用run或call方法執行完成,正常結束
—>線程拋出一個爲捕獲的Exception或Error
—>直接調用stop()方法來結束該線程——容易致使死鎖,不推薦。
不要試圖對死亡的線程使用start()方法,將會拋出異常,並不會重啓死亡的異常!