一贤笆、什么是線程
現(xiàn)代操作系統(tǒng)調(diào)度的最小單元是線程府树,在一個進(jìn)程里可以創(chuàng)建多個線程,這些線程都擁有各自的計(jì)數(shù)器偎蘸、堆棧和局部變量等屬性庄蹋,并且能夠訪問共享的內(nèi)存變量瞬内。處理器在這些線程上高速切換,讓使用者感覺到這些線程在同時執(zhí)行限书。
二虫蝶、為什么要使用多線程
- 更多的處理器核心
一個單線程程序在運(yùn)行時只能使用一個處理器核心,那么再多的處理器核心加入也無法顯著提升該程序的執(zhí)行效率倦西。相反能真,如果該程序使用多線程技術(shù),將計(jì)算邏輯分配到多個處理器核心上扰柠,就會顯著減少程序的處理時間粉铐,并且隨著更多處理器核心的加入而變得更有效率。
- 更快的響應(yīng)時間
有時我們會編寫業(yè)務(wù)較為復(fù)雜的代碼卤档。例如蝙泼,一筆訂單的創(chuàng)建,它包括插入訂單數(shù)據(jù)劝枣、生成訂單快照汤踏、發(fā)送郵件通知賣家和記錄貨品銷售數(shù)量∩诿猓可以使用多線程技術(shù)茎活,將數(shù)據(jù)一致性不強(qiáng)的操作派發(fā)給其他線程處理(也可以使用消息隊(duì)列),如生成訂單快照琢唾、發(fā)送郵件等载荔。好處是響應(yīng)用戶請求的線程能夠盡可能快地處理完成,縮短了響應(yīng)時間采桃,提升用戶體驗(yàn)懒熙。
三、線程優(yōu)先級
現(xiàn)代操作系統(tǒng)基本采用分時的形式調(diào)度運(yùn)行線程普办,操作系統(tǒng)會分出一個個時間片工扎,線程會分配到若干時間片,當(dāng)線程的時間片用完了就會發(fā)生線程調(diào)度衔蹲,等待下次分配肢娘。線程優(yōu)先級就是決定線程需要多或者少分配一些處理器資源的線程屬性。
通過一個整型成員變量priority來控制優(yōu)先級舆驶,優(yōu)先級范圍從1~10橱健,在線程構(gòu)建時可以通過setPriority(int)方法來修改線程優(yōu)先級,默認(rèn)優(yōu)先級是5沙廉。線程優(yōu)先級不能作為程序正確性的依賴拘荡,許多操作系統(tǒng)都是完全不理會Java線程對于優(yōu)先級的設(shè)定的。
四撬陵、線程的狀態(tài)
狀態(tài)名稱 | 說明 |
---|---|
NEW | 初始狀態(tài)珊皿,線程被構(gòu)建网缝,但是還沒有調(diào)用start()方法 |
RUNNABLE | 運(yùn)行狀態(tài),就緒和 運(yùn)行中兩種狀態(tài)都稱作運(yùn)行中 |
BLOCKED | 阻塞狀態(tài)蟋定,標(biāo)識線程阻塞于鎖 |
WAITING | 等待狀態(tài)粉臊,表示線程進(jìn)入等待狀態(tài),進(jìn)入該狀態(tài)表示當(dāng)前線程需要等待其他線程做出一些特定動作(通知或中斷) |
TIME_WAITING | 超時等待狀態(tài)溢吻,不同于WAITING维费,它可以在指定時間自行返回 |
TERMINATED | 終止?fàn)顟B(tài),表示當(dāng)前線程已經(jīng)執(zhí)行完畢 |
// ThreadState.java
public class ThreadState {
public static void main(String[] args) {
new Thread(new TimeWaiting(), "TimeWaitingThread").start();
new Thread(new Waiting(), "WaitingThread").start();
// 使用兩個Blocked線程, 一個獲取鎖成功, 另一個被阻塞
new Thread(new Blocked(), "BlockedThread-1").start();
new Thread(new Blocked(), "BlockedThread-2").start();
}
// 該線程不斷的進(jìn)行睡眠
static class TimeWaiting implements Runnable {
@Override
public void run() {
while (true) {
SleepUtils.second(100);
}
}
}
// 該線程在Waiting.class實(shí)例上等待
static class Waiting implements Runnable {
@Override
public void run() {
while (true) {
synchronized (Waiting.class) {
try {
Waiting.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
// 該線程在Blocked.class 實(shí)例上加鎖后,不會釋放該鎖
static class Blocked implements Runnable {
public void run() {
synchronized (Blocked.class) {
while (true) {
SleepUtils.second(100);
}
}
}
}
}
// SleepUtils.java
public class SleepUtils {
public static final void second(long seconds) {
try {
TimeUnit.SECONDS.sleep(seconds);
} catch (InterruptedException e) {
}
}
}
命令行輸入“jps”促王,得到ThreadState的進(jìn)程id(如929)后,輸入“jstack 929”而晒,嘗試查看示例進(jìn)程運(yùn)行時的線程信息:
// BlockedThread-2 線程阻塞在獲取Blocked.class示例的鎖上
"BlockedThread-2" prio=5 tid=0x00007feacb05d000 nid=0x5d03 waiting for monitor entry
[0x000000010fd58000]
java.lang.Thread.State: BLOCKED (on object monitor)
// BlockedThread-1 線程獲取到了Blocked.class的鎖
"BlockedThread-1" prio=5 tid=0x00007feacb05a000 nid=0x5b03 waiting on condition
[0x000000010fc55000]
java.lang.Thread.State: TIME_WAITING (sleeping)
// WaitingThread線程在Waiting實(shí)例上等待
"WaitingThread" prio=5 tid=0x00007feacb059800 nid=0x5903 in Object.wait()
[0x000000010fb52000]
java.lang.Thread.State: WAITING (on object monitor)
// TimeWaitingThread 線程處于超時等待
"TimeWaitingThread" prio=5 tid=0x00007feacb058800 nid=0x5703 waiting on condition
[0x000000010fa4f000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
五蝇狼、守護(hù)線程
Daemon線程是一種支持型線程,因?yàn)樗饕挥米鞒绦蛑泻笈_調(diào)度以及支持性工作倡怎。這意味著迅耘,當(dāng)一個Java虛擬機(jī)中不存在非Daemon線程的時候,Java虛擬機(jī)將會退出监署。因此颤专,不能依靠Daemon線程的finally塊中的內(nèi)容來確保執(zhí)行關(guān)閉或清理資源的邏輯。
可以通過Thread.setDaemon(true)將線程設(shè)置為Daemon線程钠乏。