簡單了解Java編程中線程的創(chuàng)建與守護(hù)線程
線程的兩種創(chuàng)建方式及優(yōu)劣比較
1、通過實現(xiàn)Runnable接口線程創(chuàng)建
(1).定義一個類實現(xiàn)Runnable接口,重寫接口中的run()方法。在run()方法中加入具體的任務(wù)代碼或處理邏輯。
(2).創(chuàng)建Runnable接口實現(xiàn)類的對象。
(3).創(chuàng)建一個Thread類的對象,需要封裝前面Runnable接口實現(xiàn)類的對象。(接口可以實現(xiàn)多繼承)
(4).調(diào)用Thread對象的start()方法,啟動線程
示例代碼:
package demo.thread;
public class TreadDemo1 implements Runnable {
private int countDown = 10;
@Override
// 在run方法中定義任務(wù)
public void run() {
while (countDown-- > 0) {
System.out.println("#" + Thread.currentThread().getName() + "("
+ countDown + ")");
}
}
public static void main(String[] args) {
// Runnable中run方法是一個空方法,并不會產(chǎn)生任何線程行為,必須顯式地將一個任務(wù)附著到線程上
TreadDemo1 tt=new TreadDemo1();
new Thread(tt).start();
new Thread(tt).start();
System.out.println("火箭發(fā)射前倒計時:");
}
}
運行結(jié)果:
火箭發(fā)射前倒計時:
#Thread-1(8) #Thread-1(7) #Thread-1(6) #Thread-1(5) #Thread-1(4) #Thread-1(3) #Thread-1(2) #Thread-1(1) #Thread-1(0) #Thread-0(9)
2、通過繼承Thread類創(chuàng)建線程
(1).首先定義一個類去繼承Thread父類,重寫父類中的run()方法。在run()方法中加入具體的任務(wù)代碼或處理邏輯。
(2).直接創(chuàng)建一個ThreadDemo2類的對象,也可以利用多態(tài)性,變量聲明為父類的類型。
(3).調(diào)用start方法,線程t啟動,隱含的調(diào)用run()方法。
示例代碼:
package demo.thread;
public class ThreadDemo2 extends Thread {
private int countDown = 10;
@Override
// 在run方法中定義任務(wù)
public void run() {
while (countDown-- > 0) {
System.out.println("#" + this.getName() + "(" + countDown + ")");
}
}
public static void main(String[] args) {
new ThreadDemo2().start();
new ThreadDemo2().start();
// 由于start方法迅速返回,所以main線程可以執(zhí)行其他的操作,此時有兩個獨立的線程在并發(fā)運行
System.out.println("火箭發(fā)射前倒計時:");
}
}
運行結(jié)果:
#Thread-0(9) #Thread-0(8) #Thread-0(7) #Thread-0(6) #Thread-0(5) #Thread-0(4) #Thread-0(3) #Thread-0(2) #Thread-0(1) #Thread-0(0)
火箭發(fā)射前倒計時:
#Thread-1(9) #Thread-1(8) #Thread-1(7) #Thread-1(6) #Thread-1(5) #Thread-1(4) #Thread-1(3) #Thread-1(2) #Thread-1(1) #Thread-1(0)
3、兩種方式的比較
首先分析兩種方式的輸出結(jié)果,同樣是創(chuàng)建了兩個線程,為什么結(jié)果不一樣呢?
使用實現(xiàn)Runnable接口方式創(chuàng)建線程可以共享同一個目標(biāo)對象 (TreadDemo1 tt=new TreadDemo1();),實現(xiàn)了多個相同線程處理同一份資源。
然后再看一段來自JDK的解釋:
Runnable 接口應(yīng)該由那些打算通過某一線程執(zhí)行其實例的類來實現(xiàn)。類必須定義一個稱為run 的無參數(shù)方法。
設(shè)計該接口的目的是為希望在活動時執(zhí)行代碼的對象提供一個公共協(xié)議。例如,Thread 類實現(xiàn)了Runnable 。激活的意思是說某個線程已啟動并且尚未停止。
此外,Runnable 為非 Thread 子類的類提供了一種激活方式。通過實例化某個Thread 實例并將自身作為運行目標(biāo),就可以運行實現(xiàn) Runnable 的類而無需創(chuàng)建 Thread 的子類。大多數(shù)情況下,如果只想重寫run() 方法,而不重寫其他 Thread 方法,那么應(yīng)使用 Runnable 接口。這很重要,因為除非程序員打算修改或增強(qiáng)類的基本行為,否則不應(yīng)為該類創(chuàng)建子類。
采用繼承Thread類方式:
(1)優(yōu)點:編寫簡單,如果需要訪問當(dāng)前線程,無需使用Thread.currentThread()方法,直接使用this,即可獲得當(dāng)前線程。
(2)缺點:因為線程類已經(jīng)繼承了Thread類,所以不能再繼承其他的父類。
采用實現(xiàn)Runnable接口方式:
(1)優(yōu)點:線程類只是實現(xiàn)了Runable接口,還可以繼承其他的類。在這種方式下,可以多個線程共享同一個目標(biāo)對象,所以非常適合多個相同線程來處理同一份資源的情況,從而可以將CPU代碼和數(shù)據(jù)分開,形成清晰的模型,較好地體現(xiàn)了面向?qū)ο蟮乃枷搿?br />
(2)缺點:編程稍微復(fù)雜,如果需要訪問當(dāng)前線程,必須使用Thread.currentThread()方法。
后臺線程(守護(hù)線程)
所謂的后臺線程,是指在程序運行的時候在后臺提供一種通用服務(wù)的線程,并且這種線程并不屬于程序中不可或缺的部分。因此當(dāng)所有的非后臺線程結(jié)束時,程序也就終止了,同時會殺死所有后臺線程。反過來說,只要有任何非后臺線程(用戶線程)還在運行,程序就不會終止。后臺線程在不執(zhí)行finally子句的情況下就會終止其run方法。后臺線程創(chuàng)建的子線程也是后臺線程。 下面是一個后臺線程的示例:
package demo.thread;
import java.util.concurrent.TimeUnit;
public class DaemonDemo implements Runnable {
@Override
public void run() {
try {
while (true) {
Thread.sleep(1000);
System.out.println("#" + Thread.currentThread().getName());
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {// 后臺線程不執(zhí)行finally子句
System.out.println("finally ");
}
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
Thread daemon = new Thread(new DaemonDemo());
// 必須在start之前設(shè)置為后臺線程
daemon.setDaemon(true);
daemon.start();
}
System.out.println("All daemons started");
try {
TimeUnit.MILLISECONDS.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
運行結(jié)果:
All daemons started #Thread-2 #Thread-3 #Thread-1 #Thread-0 #Thread-9 #Thread-6 #Thread-8 #Thread-5 #Thread-7 #Thread-4
分析:從結(jié)果可以看出,十個子線程并沒有無線循環(huán)的打印,而是在主線程(main())退出后,JVM強(qiáng)制關(guān)閉所有后臺線程。而不會有任何希望出現(xiàn)的確認(rèn)形式,如finally子句不執(zhí)行。
相關(guān)文章
Java解析http協(xié)議字符串的方法實現(xiàn)
本文主要介紹了Java解析http協(xié)議字符串的方法實現(xiàn),我們探討了如何使用Java解析HTTP協(xié)議字符串,并將其封裝成了一個HttpRequest類,具有一定的參考價值,感興趣的可以了解一下2023-09-09
Java人民幣小寫轉(zhuǎn)大寫字符串的實現(xiàn)
這篇文章主要介紹了Java人民幣小寫轉(zhuǎn)大寫字符串的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
SpringBoot集成Swagger構(gòu)建api文檔的操作
這篇文章主要介紹了SpringBoot集成Swagger構(gòu)建api文檔的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12
關(guān)于mybatis-plus插件使用時的一些問題小結(jié)
這篇文章主要給大家介紹了關(guān)于mybatis-plus插件使用時的一些問題的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2022-03-03

