1、 認識Thread和Runnable
Java中實現(xiàn)多線程有兩種途徑:繼承Thread類或者實現(xiàn)Runnable接口。Runnable是接口,建議用接口的方式生成線程,因為接口可以實現(xiàn)多繼承,況且Runnable只有一個run方法,很適合繼承。在使用Thread的時候只需繼承Thread,并且new一個實例出來,調用 start()方法即可以啟動一個線程。
Thread Test = new Thread();
Test.start();
在使用Runnable的時候需要先new一個實現(xiàn)Runnable的實例,之后啟動Thread即可。
Test impelements Runnable;
Test t = new Test();
Thread test = new Thread(t);
test.start();
總結:Thread和Runnable是實現(xiàn)java多線程的2種方式,runable是接口,thread是類,建議使用runable實現(xiàn) java多線程,不管如何,最終都需要通過thread.start()來使線程處于可運行狀態(tài)。
2、 認識Thread的start和run
1) start:
用start方法來啟動線程,真正實現(xiàn)了多線程運行,這時無需等待run方法體代碼執(zhí)行完畢而直接繼續(xù)執(zhí)行下面的代碼。通過調用Thread類的 start()方法來啟動一個線程,這時此線程處于就緒(可運行)狀態(tài),并沒有運行,一旦得到cpu時間片,就開始執(zhí)行run()方法,這里方法 run()稱為線程體,它包含了要執(zhí)行的這個線程的內(nèi)容,Run方法運行結束,此線程隨即終止。
2) run:
run()方法只是類的一個普通方法而已,如果直接調用Run方法,程序中依然只有主線程這一個線程,其程序執(zhí)行路徑還是只有一條,還是要順序執(zhí)行,還是要等待run方法體執(zhí)行完畢后才可繼續(xù)執(zhí)行下面的代碼,這樣就沒有達到寫線程的目的。
總結:調用start方法方可啟動線程,而run方法只是thread的一個普通方法調用,還是在主線程里執(zhí)行。
3、 線程狀態(tài)說明
線程狀態(tài)從大的方面來說,可歸結為:初始狀態(tài)、可運行狀態(tài)、不可運行狀態(tài)和消亡狀態(tài),具體可細分為上圖所示7個狀態(tài),說明如下:
1) 線程的實現(xiàn)有兩種方式,一是繼承Thread類,二是實現(xiàn)Runnable接口,但不管怎樣,當我們new了thread實例后,線程就進入了初始狀態(tài);
2) 當該對象調用了start()方法,就進入可運行狀態(tài);
3) 進入可運行狀態(tài)后,當該對象被操作系統(tǒng)選中,獲得CPU時間片就會進入運行狀態(tài);
4) 進入運行狀態(tài)后case就比較多,大致有如下情形:
﹒run()方法或main()方法結束后,線程就進入終止狀態(tài);
﹒當線程調用了自身的sleep()方法或其他線程的join()方法,就會進入阻塞狀態(tài)(該狀態(tài)既停止當前線程,但并不釋放所占有的資源)。當 sleep()結束或join()結束后,該線程進入可運行狀態(tài),繼續(xù)等待OS分配時間片;
﹒當線程剛進入可運行狀態(tài)(注意,還沒運行),發(fā)現(xiàn)將要調用的資源被鎖牢(synchroniza,lock),將會立即進入鎖池狀態(tài),等待獲取鎖標記(這時的鎖池里也許已經(jīng)有了其他線程在等待獲取鎖標記,這時它們處于隊列狀態(tài),既先到先得),一旦線程獲得鎖標記后,就轉入可運行狀態(tài),等待OS分配 CPU時間片;
﹒當線程調用wait()方法后會進入等待隊列(進入這個狀態(tài)會釋放所占有的所有資源,與阻塞狀態(tài)不同),進入這個狀態(tài)后,是不能自動喚醒的,必須依靠其他線程調用notify()或notifyAll()方法才能被喚醒(由于notify()只是喚醒一個線程,但我們由不能確定具體喚醒的是哪一個線程,也許我們需要喚醒的線程不能夠被喚醒,因此在實際使用時,一般都用notifyAll()方法,喚醒有所線程),線程被喚醒后會進入鎖池,等待獲取鎖標記。
﹒當線程調用stop方法,即可使線程進入消亡狀態(tài),但是由于stop方法是不安全的,不鼓勵使用,大家可以通過run方法里的條件變通實現(xiàn)線程的 stop。