摘要:一初識的線程是通過類來實現(xiàn)的。在生成線程對象,并沒有調用該對象的方法,這是線程處于創(chuàng)建狀態(tài)。如果一個線程的方法執(zhí)行結束或者調用方法后,該線程就會死亡。對于已經死亡的線程,無法再使用方法令其進入就緒。
一、初識
java的線程是通過java.lang.Thread類來實現(xiàn)的。VM啟動時會有一個由主方法所定義的線程??梢酝ㄟ^創(chuàng)建Thread的實例來創(chuàng)建新的線程。每個線程都是通過某個特定Thread對象所對應的方法run()來完成其操作的,方法run()稱為線程體。通過調用Thread類的start()方法來啟動一個線程。
在Java當中,線程通常都有五種狀態(tài),創(chuàng)建、就緒、運行、阻塞和死亡。
第一是創(chuàng)建狀態(tài)。在生成線程對象,并沒有調用該對象的start方法,這是線程處于創(chuàng)建狀態(tài)。
第二是就緒狀態(tài)。當調用了線程對象的start方法之后,該線程就進入了就緒狀態(tài),但是此時線程調度程序還沒有把該線程設置為當前線程,此時處于就緒狀態(tài)。在線程運行之后,從等待或者睡眠中回來之后,也會處于就緒狀態(tài)。
第三是運行狀態(tài)。線程調度程序將處于就緒狀態(tài)的線程設置為當前線程,此時線程就進入了運行狀態(tài),開始運行run函數(shù)當中的代碼。
第四是阻塞狀態(tài)。線程正在運行的時候,被暫停,通常是為了等待某個時間的發(fā)生(比如說某項資源就緒)之后再繼續(xù)運行。sleep,suspend,wait等方法都可以導致線程阻塞。
第五是死亡狀態(tài)。如果一個線程的run方法執(zhí)行結束或者調用stop方法后,該線程就會死亡。對于已經死亡的線程,無法再使用start方法令其進入就緒。
二、start()方法1、為什么需要start方法;它的作用是什么?
start()方法來啟動線程,真正實現(xiàn)了多線程運行。
start方法的作用就是將線程由NEW狀態(tài),變?yōu)镽UNABLE狀態(tài)。當線程創(chuàng)建成功時,線程處于NEW(新建)狀態(tài),如果你不調用start( )方法,那么線程永遠處于NEW狀態(tài)。調用start( )后,才會變?yōu)镽UNABLE狀態(tài),線程才可以運行。
2、調用start()方法后,線程是不是馬上執(zhí)行?
線程不是馬上執(zhí)行的;準確來說,調用start( )方法后,線程的狀態(tài)是“READY(就緒)”狀態(tài),而不是“RUNNING(運行中)”狀態(tài)(關于線程的狀態(tài)詳細。線程要等待CPU調度,不同的JVM有不同的調度算法,線程何時被調度是未知的。因此,start()方法的被調用順序不能決定線程的執(zhí)行順序
注意:
由于在線程的生命周期中,線程的狀態(tài)由NEW ----> RUNABLE只會發(fā)生一次,因此,一個線程只能調用start()方法一次,多次啟動一個線程是非法的。特別是當線程已經結束執(zhí)行后,不能再重新啟動。
1、run方法又是一個什么樣的方法?run方法與start方法有什么關聯(lián)?
run()方法當作普通方法的方式調用
run( )其實是一個普通方法,只不過當線程調用了start( )方法后,一旦線程被CPU調度,處于運行狀態(tài),那么線程才會去調用這個run()方法;
2、run()方法的執(zhí)行是不是需要線程調用start()方法
上面說了,run()方法是一個普通的對象方法,因此,不需要線程調用start()后才可以調用的??梢跃€程對象可以隨時隨地調用run方法。
Example1:Thread t1 = new Thread(new MyTask(1)); Thread t2 = new Thread(new MyTask(2)); t1.run(); t2.run();
上面的輸出結果是固定的:
count的值:1
count的值:2
再看另一個實例:
Thread t1 = new Thread(new MyTask()); Thread t2 = new Thread(new MyTask()); t1.start(); t2.start();
這個輸出結果不是固定的,因為線程的運行沒法預測。運行結果可能不一樣。
MyTask 類:
//實現(xiàn)Runnable接口 class MyTask implements Runnable{ int count; public MyTask(int count) { this.count=count; } @Override public void run() { System.out.println("count的值:"+count); } }Example2:
1、用start方法啟動線程
public class Main { public static void main(String[] args) { Thread t1 = new Thread(new T1()); Thread t2 = new Thread(new T2()); t1.start(); t2.start(); } } class T1 implements Runnable { public void run() { try { for(int i=0;i<10;i++){ System.out.println(i); Thread.sleep(100); //模擬耗時任務 } } catch (InterruptedException e) { e.printStackTrace(); } } } class T2 implements Runnable { public void run() { try { for(int i=0;i>-10;i--){ System.out.println(i); Thread.sleep(100); //模擬耗時任務 } } catch (InterruptedException e) { e.printStackTrace(); } } }
結果:
說明兩線程是并發(fā)執(zhí)行的。
2、先用run方法啟動線程
將上面的start()改為run()
public class Main { public static void main(String[] args) { Thread t1 = new Thread(new T1()); Thread t2 = new Thread(new T2()); t1.run(); t2.run(); } }
說明兩線程實際是順序執(zhí)行的。
通過實例1和實例和我們可以知道start方法是用于啟動線程的,可以實現(xiàn)并發(fā),而run方法只是一個普通方法,是不能實現(xiàn)并發(fā)的,只是在并發(fā)執(zhí)行的時候會調用。
說到這,不知道小伙伴們有沒有明白這兩個方法的區(qū)別,如果還有疑問,可以留言交流。
四、start()方法和run()方法源碼解析(基于JDK1.7.0_40)public synchronized void start() { // 如果線程不是"就緒狀態(tài)",則拋出異常! if (threadStatus != 0) throw new IllegalThreadStateException(); // 將線程添加到ThreadGroup中 group.add(this); boolean started = false; try { // 通過start0()啟動線程,新線程會調用run()方法 start0(); // 設置started標記=true started = true; } finally { try { if (!started) { group.threadStartFailed(this); } } catch (Throwable ignore) { } } }
public void run() { if (target != null) { target.run(); } }五、真正理解Thread類
Thread類的對象其實也是一個java對象,只不過每一個Thread類的對象對應著一個線程。Thread類的對象就是提供給用戶用于操作線程、獲取線程的信息。真正的底層線程用戶是看不到的了。
因此,當一個線程結束了,死掉了,對應的Thread的對象仍能調用,除了start( )方法外的所有方法(死亡的線程不能再次啟動),如run( )、getName( )、getPriority()等等
//簡單起見,使用匿名內部類的方法來創(chuàng)建線程 Thread thread = new Thread(){ @Override public void run() { System.out.println("Thread對象的run方法被執(zhí)行了"); } }; //線程啟動 thread.start(); //用循環(huán)去監(jiān)聽線程thread是否還活著,只有當線程thread已經結束了,才跳出循環(huán) while(thread.isAlive()){} //線程thread結束了,但仍能調用thread對象的大部分方法 System.out.println("線程"+thread.getName()+"的狀態(tài):"+thread.getState()+"---優(yōu)先級:"+thread.getPriority()); //調用run方法 thread.run(); //當線程結束時,start方法不能調用,下面的方法將會拋出異常 thread.start();
http://www.cnblogs.com/jinggo...
https://blog.csdn.net/u010568...
https://blog.csdn.net/xuxurui...
文章有不當之處,歡迎指正,你也可以關注我的微信公眾號:好好學java,獲取優(yōu)質學習資源。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://www.ezyhdfw.cn/yun/69525.html
摘要:無論它由子類覆寫提供還是由對象提供,方法最終都會新建一個線程來執(zhí)行這個方法。這種方法看上去好像復雜了好多,但其實就是通過新建類的對象來創(chuàng)建線程??偨Y在中,創(chuàng)建一個線程,有且僅有一種方式創(chuàng)建一個類實例,并調用它的方法。 前言 系列文章目錄 談到線程同步與通信,線程本身的概念是繞不開的,而進程和線程的概念已經是老生常談的話題了,一些基本的概念本文就不再討論了,本篇僅僅致力于通過源碼,了解...
摘要:另外一種方法是,將這個線程加入一個線程組,在線程組里重寫方法來處理拋出的異常,這時線程組的作用相當于實現(xiàn)了的類。使用對象處理異常格式錯誤使用線程組處理異常測試異常 感性地理解一下什么是線程? 線程這個概念其實是比較抽象的,雖然依照教科書上的說法: 進程是從系統(tǒng)獲取資源的最小單位,線程是程序執(zhí)行的最小單位。程序是靜態(tài)存在于磁盤上的一段文本,進程運行這段文本記錄的命令。 也就是說,進程從系...
摘要:例子如下可以用如下方式創(chuàng)建并運行上述子類一旦線程啟動后方法就會立即返回,而不會等待到方法執(zhí)行完畢才返回。但是,事實上方法并非是由剛創(chuàng)建的新線程所執(zhí)行的,而是被創(chuàng)建新線程的當前線程所執(zhí)行了。這是因為線程是并行執(zhí)行而非順序的。 showImg(http://segmentfault.com/img/bVbN5u); Java線程類也是一個object類,它的實例都繼承自java.lang...
摘要:是不能直接調用系統(tǒng)功能的,所以,我們沒有辦法直接實現(xiàn)多線程程序。通過查看,我們知道了有種方式實現(xiàn)多線程程序。使用的是搶占式調度模型演示如何設置和獲取線程優(yōu)先級返回線程對象的優(yōu)先級更改線程的優(yōu)先級線程默認優(yōu)先級是。線程優(yōu)先級的范圍是。 第五階段 多線程 前言: 一個場景:周末,帶著并不存在的女票去看電影,無論是現(xiàn)場買票也好,又或是手機買票也好,上一秒還有位置,遲鈍了一下以后,就顯示該座位...
閱讀 2489·2021-11-22 14:56
閱讀 11262·2021-09-08 10:45
閱讀 2117·2019-08-30 13:54
閱讀 2939·2019-08-29 16:54
閱讀 2112·2019-08-29 14:20
閱讀 1866·2019-08-29 12:25
閱讀 1950·2019-08-29 12:17
閱讀 1135·2019-08-23 18:29