新聞中心
什么是線程組
public class ThreadGroupTest {
public static void main(String[] args) {
new Thread(() -> {
System.out.println(Thread.currentThread().getThreadGroup().getName());
}).start();
System.out.println(Thread.currentThread().getThreadGroup().getName());
}
}輸出:

main
main
可以發(fā)現(xiàn)在main線程組下;
ThreadGroup是一個(gè)標(biāo)準(zhǔn)的「向下引用」的樹狀結(jié)構(gòu),這樣設(shè)計(jì)的原因是「防止"上級(jí)"線程被"下級(jí)"線程引用而無法有效地被GC回收」。
線程優(yōu)先級(jí)
線程的優(yōu)先級(jí)級(jí)別由操作系統(tǒng)決定,不同的操作系統(tǒng)級(jí)別是不一樣的,在Java中,提供了一個(gè)級(jí)別范圍1~10,方便我們?nèi)⒖?。Java默認(rèn)的線程優(yōu)先級(jí)為5,線程的執(zhí)行順序由調(diào)度程序來決定,線程的優(yōu)先級(jí)會(huì)在線程被調(diào)用之前設(shè)定。
源碼描述:
/**
* 最低級(jí)別
*/
public final static int MIN_PRIORITY = 1;
/**
* 默認(rèn)級(jí)別
*/
public final static int NORM_PRIORITY = 5;
/**
* 最高級(jí)別
*/
public final static int MAX_PRIORITY = 10;
獲取線程優(yōu)先級(jí)別
public static void main(String[] args) {
new Thread(() -> {
System.out.println("default level: {}" + Thread.currentThread().getPriority());
}).start();
}輸出: default level: {}5
設(shè)置級(jí)別
public static void main(String[] args) {
Thread t = new Thread(() -> {
System.out.println("default level: {}" + Thread.currentThread().getPriority());
});
t.start();
t.setPriority(10);
}輸出: default level: {}10
通常來講,高級(jí)別的優(yōu)先級(jí)往往會(huì)更高幾率的執(zhí)行,注意這里是概率性問題,下面我們測(cè)試一下:
public static void main(String[] args) {
Thread t = new Thread(() -> {
System.out.println("hello " + Thread.currentThread().getPriority());
System.out.println("default level: {}" + Thread.currentThread().getPriority());
});
t.setPriority(3);
Thread t1 = new Thread(() -> {
System.out.println("hello " + Thread.currentThread().getPriority());
System.out.println("default level: {}" + Thread.currentThread().getPriority());
});
t1.setPriority(7);
Thread t2 = new Thread(() -> {
System.out.println("hello " + Thread.currentThread().getPriority());
System.out.println("default level: {}" + Thread.currentThread().getPriority());
});
t2.setPriority(10);
t.start();
t1.start();
t2.start();
}
第一次輸出:
hello 7
default level: {}7
hello 10
default level: {}10
hello 3
default level: {}3
第二次:
hello 3
default level: {}3
hello 7
default level: {}7
hello 10
default level: {}10
第三次
hello 10
default level: {}10
hello 7
default level: {}7
hello 3
default level: {}3
...
發(fā)現(xiàn),不斷的嘗試之后,高級(jí)別出現(xiàn)的概率會(huì)比較靠前一點(diǎn), 所以想要借助它來完成一些特定業(yè)務(wù)的同學(xué)注意了,不建議使用,不靠譜,之前也講到,底層還是由操作系統(tǒng)調(diào)度完成
Java提供一個(gè)「線程調(diào)度器」來監(jiān)視和控制處于「RUNNABLE狀態(tài)」的線程。線程的調(diào)度策略采用「搶占式」,優(yōu)先級(jí)高的線程比優(yōu)先級(jí)低的線程會(huì)有更大的幾率優(yōu)先執(zhí)行。在優(yōu)先級(jí)相同的情況下,按照“先到先得”的原則。每個(gè)Java程序都有一個(gè)默認(rèn)的主線程,就是通過JVM啟動(dòng)的第一個(gè)線程main線程。
除了主線程之外,還有一個(gè)線程是守護(hù)線程,它的優(yōu)先級(jí)比較低。如果所有的非守護(hù)線程都結(jié)束了,這個(gè)守護(hù)線程也會(huì)自動(dòng)結(jié)束??梢越柚鼘?shí)現(xiàn)一些特定場(chǎng)景,比如手動(dòng)關(guān)閉線程的場(chǎng)景,某些場(chǎng)景下不關(guān)閉,會(huì)造成資源浪費(fèi),手動(dòng)關(guān)閉又很麻煩。這里我們可以通過setDaemon(true)指定。
public static void main(String[] args) {
Thread t = new Thread(() -> {
System.out.println("hello " + Thread.currentThread().getPriority());
System.out.println("default level: {}" + Thread.currentThread().getPriority());
});
t.setDaemon(true); // 默認(rèn)為false
t.setPriority(10);
Thread t1 = new Thread(() -> {
System.out.println("hello " + Thread.currentThread().getPriority());
System.out.println("default level: {}" + Thread.currentThread().getPriority());
});
t1.setPriority(7);
t.start();
t1.start();
}輸出:
hello 7
default level: {}7
hello 10
default level: {}10
發(fā)現(xiàn)即使指定了高級(jí)別,執(zhí)行的優(yōu)先級(jí)仍然是最低的
線程組下的優(yōu)先級(jí)
剛剛我們都是在main線程組下,舉一反三,線程組下的優(yōu)先級(jí)又是怎么樣的呢下面,測(cè)試一下:
public static void main(String[] args) {
// 指定 name 為 g1的線程組
ThreadGroup group = new ThreadGroup("g1");
group.setMaxPriority(4);
Thread t = new Thread(group, () -> {
System.out.println("hello " + Thread.currentThread().getPriority());
System.out.println("default level: {}" + Thread.currentThread().getPriority());
}, "t0");
t.setPriority(10);
t.start();
}輸出:
hello 4
default level: {}4
發(fā)現(xiàn),在g1線程組下指定了最大優(yōu)先級(jí)后,線程t0的優(yōu)先級(jí)最大級(jí)別只能是4, 所以這也是使用線程組的好處。
我們可以通過如下方式復(fù)制線程組, ThreadGroup提供了enumerate方法:
public static void main(String[] args) throws InterruptedException {
// 指定 name 為 g1的線程組
ThreadGroup group = new ThreadGroup("g1");
group.setMaxPriority(4);
Thread t = new Thread(group, () -> {
System.out.println("hello " + Thread.currentThread().getPriority());
System.out.println("default level: {}" + Thread.currentThread().getPriority());
}, "t0");
t.setPriority(10);
t.start();
// 復(fù)制線程組
System.out.println(group.activeCount()); // 1
Thread[] list = new Thread[group.activeCount()];
group.enumerate(list);
Thread.sleep(3000);
System.out.println(list[0].getName()); // 輸出 t0
}
統(tǒng)一異常捕獲
public static void main(String[] args) {
// 指定 name 為 g1的線程組
ThreadGroup group = new ThreadGroup("g1") {
// 統(tǒng)一異常捕獲
public void uncaughtException(Thread t, Throwable e) {
System.out.println(t.getName() + ": " + e.getMessage()); // t0: 我出錯(cuò)了
}
};
group.setMaxPriority(4);
Thread t = new Thread(group, () -> {
System.out.println("hello " + Thread.currentThread().getPriority());
System.out.println("default level: {}" + Thread.currentThread().getPriority());
throw new RuntimeException("我出錯(cuò)了");
}, "t0");
t.setPriority(10);
t.start();
}
向下引用的樹狀數(shù)據(jù)結(jié)構(gòu)
線程組的內(nèi)部其實(shí)不單單可以放線程,其實(shí)也可以放其它線程組,我們看下源碼定義
public static void main(String[] args) {
// 指定 name 為 g1的線程組
ThreadGroup group = new ThreadGroup("g1") {
// 統(tǒng)一異常捕獲
public void uncaughtException(Thread t, Throwable e) {
System.out.println(t.getName() + ": " + e.getMessage()); // t0: 我出錯(cuò)了
}
};
group.setMaxPriority(4);
Thread t = new Thread(group, () -> {
System.out.println("hello " + Thread.currentThread().getPriority());
System.out.println("default level: {}" + Thread.currentThread().getPriority());
throw new RuntimeException("我出錯(cuò)了");
}, "t0");
t.setPriority(10);
t.start();
}這里大家可以大膽去猜測(cè)一下,為什么要采用這種數(shù)據(jù)結(jié)構(gòu)其實(shí)你通過源碼發(fā)現(xiàn),它的內(nèi)部很多地方都調(diào)用了checkAccess方法,特別是在set操作,字面意思是檢查是否有權(quán)限,我看下這個(gè)方法。
public final void checkAccess() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkAccess(this);
}
}它調(diào)用了一個(gè)SecurityManager, 它是Java的安全管理器,它允許應(yīng)用程序在執(zhí)行一個(gè)可能不安全或敏感的操作前確定該操作是什么,以及是否是在允許執(zhí)行該操作的安全上下文中執(zhí)行它。應(yīng)用程序可以允許或不允許該操作??偟膩碚f就是保證安全性。
通過上面的了解,我們應(yīng)該知道為什么要用這種樹狀結(jié)構(gòu)了。它都是一層一層級(jí)別的控制,這么做方便去管理,提高安全性,出了問題也能很快的定位到。就像公司的人員組織架構(gòu)一樣,一切都是為了管理好公司。
結(jié)束語
本篇內(nèi)容到這里就結(jié)束了, 大家自己一定要多去理解,不要去背,。
分享文章:面試官:有了解過線程組和線程優(yōu)先級(jí)嗎?
URL鏈接:http://m.5511xx.com/article/djcgdsp.html


咨詢
建站咨詢
