初步學(xué)習(xí)Java中線程的實(shí)現(xiàn)與生命周期
線程的實(shí)現(xiàn)
在Java中通過(guò)run方法為線程指明要完成的任務(wù),有兩種技術(shù)來(lái)為線程提供run方法:
1.繼承Thread類(lèi)并重寫(xiě)它的run方法。之后創(chuàng)建這個(gè)子類(lèi)的對(duì)象并調(diào)用start()方法。
2.通過(guò)定義實(shí)現(xiàn)Runnable接口的類(lèi)進(jìn)而實(shí)現(xiàn)run方法。這個(gè)類(lèi)的對(duì)象在創(chuàng)建Thread的時(shí)候作為參數(shù)被傳入,然后調(diào)用start()方法。
Thread類(lèi)是專(zhuān)門(mén)用來(lái)創(chuàng)建線程和對(duì)線程進(jìn)行操作的類(lèi)。當(dāng)某個(gè)類(lèi)繼承了Thread類(lèi)之后,該類(lèi)就叫做一個(gè)線程類(lèi)。
兩種方法均需執(zhí)行線程的start()方法為線程分配必須的系統(tǒng)資源、調(diào)度線程運(yùn)行并執(zhí)行線程的run()方法。
start()方法是啟動(dòng)線程的唯一的方法。start()方法首先為線程的執(zhí)行準(zhǔn)備好系統(tǒng)資源,然后再去調(diào)用run()方法。一個(gè)線程只能啟動(dòng)一次,再次啟動(dòng)就不合法了。
run()方法中放入了線程的工作,即我們要這個(gè)線程去做的所有事情。缺省狀況下run()方法什么也不做。
在具體應(yīng)用中,采用哪種方法來(lái)構(gòu)造線程要視情況而定。通常,當(dāng)一個(gè)線程已經(jīng)繼承了另一個(gè)類(lèi)時(shí),就應(yīng)該用第二種方法來(lái)構(gòu)造,即實(shí)現(xiàn)Runnable接口。
下面給出兩個(gè)例子來(lái)說(shuō)明線程的兩種實(shí)現(xiàn)方法,每個(gè)例子中都有兩個(gè)線程:\
public class ThreadTest1 { public static void main(String[] args) { Thread1 thread1 = new Thread1(); Thread2 thread2 = new Thread2(); thread1.start(); thread2.start(); } } class Thread1 extends Thread { @Override public void run() { for (int i = 0; i < 100; ++i) { System.out.println("Hello World: " + i); } } } class Thread2 extends Thread { @Override public void run() { for (int i = 0; i < 100; ++i) { System.out.println("Welcome: " + i); } } } public class ThreadTest2 { public static void main(String[] args) { // 線程的另一種實(shí)現(xiàn)方法,也可以使用匿名的內(nèi)部類(lèi) Thread thread1 = new Thread(new MyThread1()); thread1.start(); Thread thread2 = new Thread(new MyThread2()); thread2.start(); } } class MyThread1 implements Runnable { @Override public void run() { for (int i = 0; i < 100; ++i) { System.out.println("Hello: " + i); } } } class MyThread2 implements Runnable { @Override public void run() { for (int i = 0; i < 100; ++i) { System.out.println("Welcome: " + i); } } }
Thread類(lèi)剖析
Thread類(lèi)也實(shí)現(xiàn)了Runnable接口,因此實(shí)現(xiàn)了接口中的run()方法。
當(dāng)生成一個(gè)線程對(duì)象時(shí),如果沒(méi)有為其指定名字,那么線程對(duì)象的名字將使用如下形式:Thread-number,該number是自動(dòng)增加的數(shù)字,并被所有的Thread對(duì)象所共享,因?yàn)樗且粋€(gè)static的成員變量。
當(dāng)使用第一種方式(繼承Thread的方式)來(lái)生成線程對(duì)象時(shí),我們需要重寫(xiě)run()方法,因?yàn)門(mén)hread類(lèi)的run()方法此時(shí)什么事情也不做。
當(dāng)使用第二種方式(實(shí)現(xiàn)Runnable接口的方式)來(lái)生成線程對(duì)象時(shí),我們需要實(shí)現(xiàn)Runnable接口的run()方法,然后使用new Thread(new MyRunnableClass())來(lái)生成線程對(duì)象(MyRunnableClass已經(jīng)實(shí)現(xiàn)了Runnable接口),這時(shí)的線程對(duì)象的run()方法會(huì)調(diào)用MyRunnableClass的run()方法。
停止線程
線程的消亡不能通過(guò)調(diào)用stop()命令,而是讓run()方法自然結(jié)束。stop()方法是不安全的,已經(jīng)廢棄。
停止線程推薦的方式:設(shè)定一個(gè)標(biāo)志變量,在run()方法中是一個(gè)循環(huán),由該標(biāo)志變量控制循環(huán)是繼續(xù)執(zhí)行還是跳出;循環(huán)跳出,則線程結(jié)束。
如代碼例子中所示:
public class ControlThreadTest { MyThreadClass r = new MyThreadClass(); Thread t = new Thread(r); public void startThread() { t.start(); } public void stopThread() { r.stopRunning(); } } class MyThreadClass implements Runnable { private boolean flag = true; @Override public void run() { while (flag) { System.out.println("Do something."); } } public void stopRunning() { flag = false; } }
線程的生命周期及優(yōu)先級(jí)
線程的生命周期
線程的生命周期:一個(gè)線程從創(chuàng)建到消亡的過(guò)程。
如下圖,表示線程生命周期中的各個(gè)狀態(tài):
線程的生命周期可以分為四個(gè)狀態(tài):
1.創(chuàng)建狀態(tài):
當(dāng)用new操作符創(chuàng)建一個(gè)新的線程對(duì)象時(shí),該線程處于創(chuàng)建狀態(tài)。
處于創(chuàng)建狀態(tài)的線程只是一個(gè)空的線程對(duì)象,系統(tǒng)不為它分配資源。
2.可運(yùn)行狀態(tài):
執(zhí)行線程的start()方法將為線程分配必須的系統(tǒng)資源,安排其運(yùn)行,并調(diào)用線程體——run()方法,這樣就使得該線程處于可運(yùn)行狀態(tài)(Runnable)。
這一狀態(tài)并不是運(yùn)行中狀態(tài)(Running),因?yàn)榫€程也許實(shí)際上并未真正運(yùn)行。
3.不可運(yùn)行狀態(tài):
當(dāng)發(fā)生下列事件時(shí),處于運(yùn)行狀態(tài)的線程會(huì)轉(zhuǎn)入到不可運(yùn)行狀態(tài):
調(diào)用了sleep()方法;
線程調(diào)用wait()方法等待特定條件的滿足;
線程輸入/輸出阻塞。
返回可運(yùn)行狀態(tài):
處于睡眠狀態(tài)的線程在指定的時(shí)間過(guò)去后;
如果線程在等待某一條件,另一個(gè)對(duì)象必須通過(guò)notify()或notifyAll()方法通知等待線程條件的改變;
如果線程是因?yàn)檩斎胼敵鲎枞?,等待輸入輸出完成?/p>
4.消亡狀態(tài):
當(dāng)線程的run()方法執(zhí)行結(jié)束后,該線程自然消亡。
線程的優(yōu)先級(jí)
1.線程的優(yōu)先級(jí)及設(shè)置
線程的優(yōu)先級(jí)是為了在多線程環(huán)境中便于系統(tǒng)對(duì)線程的調(diào)度,優(yōu)先級(jí)高的線程將優(yōu)先執(zhí)行。
一個(gè)線程的優(yōu)先級(jí)設(shè)置遵從以下原則:
線程創(chuàng)建時(shí),子繼承父的優(yōu)先級(jí)。
線程創(chuàng)建后,可通過(guò)調(diào)用setPriority()方法改變優(yōu)先級(jí)。
線程的優(yōu)先級(jí)是1-10之間的正整數(shù)。
1- MIN_PRIORITY
10-MAX_PRIORITY
5-NORM_PRIORITY
如果什么都沒(méi)有設(shè)置,默認(rèn)值是5。
但是不能依靠線程的優(yōu)先級(jí)來(lái)決定線程的執(zhí)行順序。
2.線程的調(diào)度策略
線程調(diào)度器選擇優(yōu)先級(jí)最高的線程運(yùn)行。但是,如果發(fā)生以下情況,就會(huì)終止線程的運(yùn)行:
線程體中調(diào)用了yield()方法,讓出了對(duì)CPU的占用權(quán)。
線程體中調(diào)用了sleep()方法,使線程進(jìn)入睡眠狀態(tài)。
線程由于I/O操作而受阻塞。
另一個(gè)更高優(yōu)先級(jí)的線程出現(xiàn)。
在支持時(shí)間片的系統(tǒng)中,該線程的時(shí)間片用完。
相關(guān)文章
Java加載資源文件時(shí)的路徑問(wèn)題的解決辦法
今天偶然看到一篇關(guān)于tomcat加載servlet的文章,不由得想起了java加載資源文件的路徑問(wèn)題,資源文件可以使xml,properties,圖片等,可以是任何文件2013-04-04IntelliJ IDEA 無(wú)法正常使用SVN的問(wèn)題和完美解決辦法
這篇文章主要介紹了IntelliJ IDEA 無(wú)法正常使用SVN的問(wèn)題和解決辦法,本文給大家分享完美解決方案,通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-08-08深入了解Java8中的時(shí)區(qū)日期時(shí)間
Java?在?java.time?包中也提供了幾個(gè)類(lèi)用于處理需要關(guān)注時(shí)區(qū)的日期時(shí)間?API,本文將通過(guò)簡(jiǎn)單的示例講講它們的用法,需要的可以參考一下2023-04-04帶有@Transactional和@Async的循環(huán)依賴問(wèn)題的解決
這篇文章主要介紹了帶有@Transactional和@Async的循環(huán)依賴問(wèn)題的解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04El表達(dá)式使用問(wèn)題javax.el.ELException:Failed to parse the expression
今天小編就為大家分享一篇關(guān)于Jsp El表達(dá)式使用問(wèn)題javax.el.ELException:Failed to parse the expression的解決方式,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-12-12