1. 線程簡介
1.1 什么是線程
線程是現(xiàn)代操作系統(tǒng)能夠進行調(diào)度和運算的基本單位
在一個進程中可以創(chuàng)建多個線程, 這些線程都有各自的計數(shù)器, 堆棧和局部變量等屬性, 并且能夠訪問共享的內(nèi)存變量, CPU在這些線程上高速切換, 讓使用者感覺到這些線程在同時執(zhí)行
1.2 .為什么使用多線程
- 處理器核心數(shù)量越來越多, 超線程技術(shù)的廣泛應用
- 更快的影響時間, 多線程處理復雜業(yè)務
- 提高CPU利用率
1.3 線程優(yōu)先級
現(xiàn)代操作系統(tǒng)基本采用時分的形式調(diào)度運行的線程, 操作系統(tǒng)會分出一個個時間片, 線程會分配到若干時間片, 當線程的時間片用完了就會發(fā)生線程調(diào)度, 并等待下次分配
線程分配到的時間片多少也就決定了線程使用處理器資源的多少, 線程優(yōu)先級作用是控制分配給線程的時間片多一些或少一些
在java中, 通過priority屬性來控制線程優(yōu)先級, 優(yōu)先級范圍1~10, 默認優(yōu)先級為5, 優(yōu)先級高的線程分配時間片的數(shù)量要多余優(yōu)先級低的線程
在不同的JVM以及操作系統(tǒng)上, 線程調(diào)度會存在差異, 有些操作系統(tǒng)甚至會忽略對線程優(yōu)先級的設定, 所以優(yōu)先級不能作為程序正確性的依賴
1.4 多線程缺點
- 線程的管理以及線程上下文切換占用額外資源
- 線程導致的死鎖,共享資源的競爭等操作導致等待時間過長
- 相應的線程不安全的問題
1.5 線程的生命周期

| 狀態(tài)名稱 | 說明 |
|---|---|
| 新建狀態(tài)(new) | 線程被構(gòu)建, 還沒有調(diào)用start()方法 |
| 就緒狀態(tài)(runnable) | 調(diào)用start()方法之后, 操作系統(tǒng)調(diào)度, 準備就緒 |
| 運行狀態(tài)(running) | 操作系統(tǒng)執(zhí)行線程 |
| 阻塞狀態(tài)(blocked) | 線程阻塞于鎖 |
| 等待狀態(tài)(waiting) | 線程等待其他線程通知或者中斷等操作 |
| 超時等待狀態(tài)(time_waiting) | 等待其他線程通知或者中斷等操作, 可以超時自動返回 |
| 終止狀態(tài)(terminated) | 線程執(zhí)行完畢 |
各種狀態(tài)對應的java代碼
- 阻塞狀態(tài)
- 等待進入synchronized代碼塊和方法
- 等待狀態(tài)和喚醒
- Object.wait()和Object.notify()
- Thread.join()
- LockSupport.park()和LockSupport.unpark(Thread)
- 等待超時
- Thread.sleep(long)
- Object.wait(long)
- Thread.join(long)
- LockSupport.parkNanos()
- LockSupport.parkUntil()
1.6 Daemon線程
Daemon線程是一種支持型線程, 主要被用作程序中后臺調(diào)度以及支持型工作
當一個虛擬機只有Daemon線程的時候, java虛擬機將會被退出, 所以Daemon線程的finally語句不一定會執(zhí)行
Thread.setDaemon(true)將線程設置為Daemon線程
public class DaemonExample {
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
//線程sleep 1秒
//這時候main函數(shù)已經(jīng)執(zhí)行完成, JVM發(fā)現(xiàn)沒有非Daemon線程
//JVM直接退出, 而不會執(zhí)行finally語句
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("DeamonThread finally finish.");
}
}
});
thread.setDaemon(true);
thread.start();
}
}
2. 實現(xiàn)多線程的三種方法
- 繼承Thread類
- 實現(xiàn)Runnable接口
- 實現(xiàn)Callable接口,配合FutureTask類
2.1 繼承Thread類
//繼承Thread接口
public class ThreadTest extends Thread {
@Override
public void run() {
System.out.println("hello,thread!");
}
public static void main(String[] args) {
Thread t1 = new ThreadTest();
t1.start();
}
}
運行結(jié)果
hello,thread!
2.2 實現(xiàn)Runnable接口
//實現(xiàn)Runable接口
public class RunableTest implements Runnable {
@Override
public void run() {
System.out.println("hello,runnable!");
}
public static void main(String[] args) {
RunableTest r = new RunableTest();
Thread t2 = new Thread(r);
t2.start();
}
}
運行結(jié)果
hello,runnable!
2.3 實現(xiàn)Callable接口
//實現(xiàn)Callable接口
public class CallableTest implements Callable<String> {
@Override
public String call() throws Exception {
return "hello,callable!";
}
public static void main(String[] args) {
CallableTest callable = new CallableTest();
//使用FutureTask,可以獲取多線程返回值
RunnableFuture<String> rf = new FutureTask<>(callable);
//線程start()
Thread t3 = new Thread(rf);
t3.start();
try {
System.out.println(rf.get());
} catch (Exception e) {
e.printStackTrace();
}
}
}
運行結(jié)果
hello,callable!
FutureTask的繼承關(guān)系

//FutureTask實現(xiàn)了Runnable接口
//所以使用Thread來處理
public class FutureTask<V> implements RunnableFuture<V> {
/**
* 構(gòu)造一個FutureTask對象
* @param callable 傳入的callable實例
*/
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW;
}
}
三種實現(xiàn)方式的聯(lián)系與區(qū)別
- Thread類繼承了Runnable接口
- Thread類使用了裝飾者模式,內(nèi)部的run方法實際是調(diào)用的是Runnable的run方法
- RunnableFuture繼承了Runnable和Future接口
- 實例化一個Thread對象,然后調(diào)用其start方法,線程進入就緒狀態(tài)
2.4 線程中斷
中斷可以理解為線程的一個標識位屬性, 表示一個運行中的線程是否被其他線程進行了中斷操作 可以使用那么interrupt()方法進行復位
interrupt()方法實際作用是, 給受阻塞的線程ThreadA設置一個中斷信號, 在線程ThreadB中, 調(diào)用了ThreadA.interrupt()方法, 其執(zhí)行順序如下
- 如果線程ThreadA沒有被阻塞, 那么interrupt()方法將不會起作用, 當線程ThreadA執(zhí)行到wait(), sleep(), join()方法時, 才會拋出InterruptedException, 然后退出阻塞狀態(tài)
- 如果線程ThreadA被阻塞 那么被執(zhí)行interrupt()方法的線程會拋出InterruptedException, 然后退出阻塞狀態(tài)
- 線程的sleep(), join()和Object#wait方法會不斷檢查線程中斷狀態(tài)的值
2.4.1 sleep和interrupt
public class InterruptDemo {
// 兩個全局線程對象, threadB用來interrupt ThreadA
static Thread threadA = new Thread(new ThreadA());
static Thread threadB = new Thread(new ThreadB());
static Logger logger = Logger.getLogger("InterruptDemo");
public static void main(String[] args) {
threadA.start();
threadB.start();
}
// 線程A, 先for循環(huán)一秒鐘, 在sleep一秒鐘
// 觀察interrupt()之后的執(zhí)行順序
static class ThreadA implements Runnable {
@Override
public void run() {
logger.info("threadA start, isInterrupted = " + threadA.isInterrupted());
// threadA for循環(huán)一秒鐘
long startTime = System.currentTimeMillis();
// threadA for循環(huán)一秒鐘
long startTime = System.currentTimeMillis();
for (;;)
if (System.currentTimeMillis() - startTime > 1000) break;
logger.info("after for loop, threadA isInterrupted = " + threadA.isInterrupted());
// threadA sleep 一秒鐘
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
logger.severe("threadA InterruptedException " + e.getMessage() + ", isInterrupted = "
+ threadA.isInterrupted());
}
logger.info("after threadA sleep isInterrupted = " + threadA.isInterrupted());
}
}
// 線程B, 用來中斷線程A
static class ThreadB implements Runnable {
@Override
public void run() {
logger.info("before threadB interrupt threadA");
// 中斷threadA
threadA.interrupt();
logger.info("after threadB interrupt threadA, threadA isInterrupted = " + threadA.isInterrupted());
}
}
}
執(zhí)行結(jié)果
10:57:07 thread.InterruptDemo$ThreadA run
信息: threadA start, isInterrupted = false
10:57:07 thread.InterruptDemo$ThreadB run
信息: before threadB interrupt threadA
10:57:07 thread.InterruptDemo$ThreadB run
信息: after threadB interrupt threadA, threadA isInterrupted = true
10:57:08 thread.InterruptDemo$ThreadA run
信息: after for loop, threadA isInterrupted = true
10:57:08 thread.InterruptDemo$ThreadA run
嚴重: threadA InterruptedException sleep interrupted, isInterrupted = false
10:57:08 thread.InterruptDemo$ThreadA run
信息: after threadA sleep isInterrupted = false
結(jié)果分析
- threadA開始執(zhí)行的時候, isInterrupted默認為false
- threadB執(zhí)行了threadA.interrupte()之后, threadA.isInterrupted()被設置為true, threadA處于中斷狀態(tài)
- 此時線程A繼續(xù)執(zhí)行for循環(huán), 并沒有拋出InterruptedException
- 然后在threadA.sleep()時候, 拋出InterruptedException, 并將isInterrupted復位為false
- threadA并沒有進入阻塞狀態(tài), 而是繼續(xù)執(zhí)行后續(xù)代碼
2.4.2 join和interrupt
public class InterruptDemo {
// 兩個全局線程對象, threadB用來interrupt ThreadA
static Thread threadA = new Thread(new ThreadA());
static Thread threadB = new Thread(new ThreadB());
static Logger logger = Logger.getLogger("InterruptDemo");
public static void main(String[] args) {
threadA.start();
threadB.start();
}
// threadA啟動后執(zhí)行threadB.join()
// 等待threadB執(zhí)行完成, threadA再繼續(xù)執(zhí)行
static class ThreadA implements Runnable {
@Override
public void run() {
logger.info("threadA start, isInterrupted = " + threadA.isInterrupted());
try {
//threadA會等待threadB執(zhí)行完成, 再繼續(xù)執(zhí)行
threadB.join();
} catch (InterruptedException e) {
logger.severe("threadA InterruptedException " + e.getMessage() + ", isInterrupted = "
+ threadA.isInterrupted());
}
// threadA for循環(huán)一秒鐘
long startTime = System.currentTimeMillis();
for (;;)
if (System.currentTimeMillis() - startTime > 1000) break;
logger.info("after for loop, threadA isInterrupted = " + threadA.isInterrupted());
}
}
// 線程B, 用來中斷線程A
static class ThreadB implements Runnable {
@Override
public void run() {
logger.info("before threadB interrupt threadA");
// 中斷threadA
threadA.interrupt();
logger.info("after threadB interrupt threadA, threadA isInterrupted = " + threadA.isInterrupted());
}
}
}
執(zhí)行結(jié)果
10:57:07 thread.InterruptDemo$ThreadA run
信息: threadA start, isInterrupted = false
10:57:07 thread.InterruptDemo$ThreadB run
信息: before threadB interrupt threadA
10:57:07 thread.InterruptDemo$ThreadB run
信息: after threadB interrupt threadA, threadA isInterrupted = true
10:57:08 thread.InterruptDemo$ThreadA run
嚴重: threadA InterruptedException null, isInterrupted = false
10:57:08 thread.InterruptDemo$ThreadA run
信息: after for loop, threadA isInterrupted = false
結(jié)果分析
- threadA開始執(zhí)行的時候, isInterrupted默認為false
- threadA執(zhí)行threadB.join()之后, 會等待threadB執(zhí)行結(jié)束,
- threadB執(zhí)行了threadA.interrupte()之后, threadA.isInterrupted()被設置為true, threadA于中斷狀態(tài)
- 此時theadA處于等待狀態(tài), 拋出InterruptedException, 并將isInterrupted復位為false
- threadA沒有等待threadB執(zhí)行完成, 而是立即恢復, 繼續(xù)執(zhí)行后續(xù)代碼
2.4.3 wait和interrupt
public class InterruptDemo {
// 兩個全局線程對象, threadB用來interrupt ThreadA
static Thread threadA = new Thread(new ThreadA());
static Thread threadB = new Thread(new ThreadB());
static Logger logger = Logger.getLogger("InterruptDemo");
//lock鎖
static Object lock = new Object();
public static void main(String[] args) {
threadA.start();
threadB.start();
}
// 線程A,
static class ThreadA implements Runnable {
@Override
public void run() {
logger.info("threadA start, isInterrupted = " + threadA.isInterrupted());
synchronized (lock) {
try {
//等待其他線程喚醒
lock.wait();
} catch (InterruptedException e) {
logger.severe("threadA InterruptedException " + e.getMessage() + ", isInterrupted = "
+ threadA.isInterrupted());
}
logger.info("after threadA wait, isInterrupted = " + threadA.isInterrupted());
}
}
}
// 線程B, 用來中斷線程A
static class ThreadB implements Runnable {
@Override
public void run() {
logger.info("before threadB interrupt threadA");
// 中斷threadA
threadA.interrupt();
logger.info("after threadB interrupt threadA, threadA isInterrupted = " + threadA.isInterrupted());
}
}
}
執(zhí)行結(jié)果
10:57:07 thread.InterruptDemo$ThreadA run
信息: threadA start, isInterrupted = false
10:57:07 thread.InterruptDemo$ThreadB run
信息: before threadB interrupt threadA
10:57:07 thread.InterruptDemo$ThreadB run
信息: after threadB interrupt threadA
10:57:08 thread.InterruptDemo$ThreadA run
嚴重: after threadB interrupt threadA, threadA isInterrupted = true
10:57:08 thread.InterruptDemo$ThreadA run
信息: after threadA wait, isInterrupted = false
結(jié)果分析
- threadA開始執(zhí)行的時候, isInterrupted默認為false
- threadA鎖住lock對象, 然后執(zhí)行l(wèi)ock.wait(), threadA進入等待狀態(tài), 等待其他線程喚醒
- threadB執(zhí)行了threadA.interrupte()之后, threadA.isInterrupted()被設置為true, threadA處于中斷狀態(tài)
- 此時theadA處于等待狀態(tài), 拋出InterruptedException, 并將isInterrupted復位為false
- threadA恢復執(zhí)行
2.4.4 線程終結(jié)和interrupt
如果一個線程threadA已經(jīng)處于終結(jié)狀態(tài), 即使該線程正處于中斷狀態(tài), 在調(diào)用threadA.isInterrupted()會返回false
public class InterruptDemo {
public static void main(String[] args) throws InterruptedException {
Thread threadA = new Thread(() -> {
System.out.println("threadA run");
});
threadA.start();
//threadA中斷
threadA.interrupt();
//主線程等待threadA執(zhí)行結(jié)束
threadA.join();
System.out.println("after threadB interrupt threadA, threadA isInterrupted = " + threadA.isInterrupted());
}
}
運行結(jié)果
threadA run
after threadB interrupt threadA, threadA isInterrupted = false
2.4.5 Thread#interrupt源碼簡介
public class Thread implements Runnable {
/**
* 判斷線程是否被中斷過
* 不復位線程中斷標記位
*/
public boolean isInterrupted() {
return isInterrupted(false);
}
/**
* 中斷線程, 并復位線程中斷標記位
* @return 線程是否被打斷
*/
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
/**
* 中斷this線程
*/
public void interrupt() {
//判斷this線程是否有權(quán)限訪問Thread.currentThread
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
interrupt0();
b.interrupt(this);
return;
}
}
interrupt0();
}
private native boolean isInterrupted(boolean ClearInterrupted);
public static native void sleep(long millis) throws InterruptedException;
}
2.4.5 Thread#interrupt使用場景
安全地終止線程, interrupt操作對進行中的線程沒有影響, 但是會打斷線程的等待, 最合適用來取消或者停止任務, 例如ThreadPoolExecutor#shutdown()就通過調(diào)用interrupt方法, 讓線程快速執(zhí)行完成, 最后再終止線程池中的任務
3. 線程間通信
每個線程擁有自己的棧空間, 相互配合的話就需要實現(xiàn)線程間通信
3.1 等待/通知機制
wait, notify, notifyAll都是Object類的final native方法
public class Object {
/**
* 在同步代碼塊中,持有當前對象鎖的線程threadWait,
* 放棄對象鎖,進入waiting狀態(tài), 線程被放到等待隊列WaitQueue中
*
* 直到其他持有對象鎖的線程threadNotify,執(zhí)行notify或notifyAll方法, 喚醒等待隊列中的一個或所有線程,
* 線程從等待隊列WaitQueue中移到同步隊列SynchronizedQueue,
* 線程從waiting狀態(tài)進入blocked狀態(tài), 等到threadNotify執(zhí)行結(jié)束, 同步隊列中的線程開始爭奪對象鎖,
* 獲取到對象鎖之后, 獲取到鎖的線程會繼續(xù)執(zhí)行
*/
public final void wait() throws InterruptedException {
wait(0);
}
/**
* 在同步代碼塊中,持有當前對象鎖的線程threadWait,
* 放棄對象鎖,進入waiting狀態(tài), 線程被放到等待隊列WaitQueue中
*
* 直到其他持有對象鎖的線程threadNotify,執(zhí)行notify或notifyAll方法, 喚醒等待隊列中的一個或所有線程,
* 或者線程等待超時
* 線程從等待隊列WaitQueue中移到同步隊列SynchronizedQueue,
* 線程從waiting狀態(tài)進入blocked狀態(tài), 等到threadNotify執(zhí)行結(jié)束, 同步隊列中的線程開始爭奪對象鎖,
* 獲取到對象鎖之后, 獲取到鎖的線程會繼續(xù)執(zhí)行
*/
public final native void wait(long timeout) throws InterruptedException;
/**
* 在同步代碼塊中,持有當前對象鎖的線程threadNotify,
* 喚醒一個處于waiting狀態(tài)的線程threadWait
*
* 線程threadWait從等待隊列WaitQueue移到同步隊列SynchronizedQueue,
* threadWait線程從waiting狀態(tài)進入blocked狀態(tài)
*
* 等到線程threadNotify同步代碼塊執(zhí)行結(jié)束, 放棄對象鎖
* threadWait線程獲取到對象鎖, 開始執(zhí)行同步代碼
*/
public final native void notify();
/**
* 在同步代碼塊中,持有當前對象鎖的線程threadNotify,
* 喚醒所有處于waiting狀態(tài)的線程
* 線程從等待隊列WaitQueue移到同步隊列SynchronizedQueue,
* 線程從waiting狀態(tài)進入blocked狀態(tài)
*
* 等到線程threadNotify同步代碼塊執(zhí)行結(jié)束, 放棄對象鎖
* 被喚醒的多個線程爭奪對象鎖, 獲取到對象鎖的線程, 開始執(zhí)行同步代碼
*/
public final native void notifyAll();
}
- 使用wait, notify和notifyAll方法時需要先對對象加鎖
- 調(diào)用wait之后, 線程由runnabe狀態(tài)轉(zhuǎn)為waiting狀態(tài), 并將線程放入等待隊列
- notify和notifyAll方法調(diào)用后, 等待線程依舊不會從wait()返回, 需要等待調(diào)用notify或notifyAll方法的線程釋放鎖之后, 等待線程才有機會從wait返回
- notify方法將等待隊列中的一個等待線程從等待隊列WaitQueue中移到同步隊列SynchronizedQueue中, notifyAll方法則是將等待隊列WaitQueue中的所有線程移到同步隊列SynchronizedQueue中, 被移動的線程狀態(tài)有waiting狀態(tài)變?yōu)閎locked狀態(tài)
- 從wait方法返回的前期是獲得了調(diào)用對象的鎖
等待/通知經(jīng)典范式
- 等待方:
- 獲取對象鎖
- 如果條件不滿足, 那么調(diào)用對象的wait()方法, 被通知后仍要檢查條件
- 條件滿足則執(zhí)行對應邏輯
synchronized(object){ while(條件不滿足){ object.wait(); } doSomething(); } - 通知方
- 獲取對象鎖
- 改變條件
- 通知等待線程
synchronized(object){ doSomething2(); 改變條件 object.notifyAll(); }
3.2 管道輸入流/輸出流
管道輸入/輸出流主要用于線程之間的數(shù)據(jù)傳輸
PipedOutputStream/PipedInputStream管道字節(jié)流, PipedReader/PipedWriter管道字符流
如下: 我們創(chuàng)建了一個輸入線程, 用來獲取控制臺的輸入的字符串, 保存到內(nèi)存中, 然后創(chuàng)建了一個打印線程, 用于獲取內(nèi)存中保存的控制臺字符串, 然后打印字符串
public class PipedExample {
public static void main(String[] args) {
//實例化輸入和打印線程
Inputer inputer = new Inputer();
Thread inputThread = new Thread(inputer);
Thread printThread = new Thread(new Printer(inputer));
//啟動線程
inputThread.start();
printThread.start();
}
//打印線程
private static class Printer implements Runnable {
//PipedReader用于讀取流, 并打印出來
private PipedReader in = new PipedReader();
public Printer(Inputer inputer) {
try {
//PipedReader和PipedWriter必須先connect
inputer.out.connect(in);
} catch (IOException e) {}
}
@Override
public void run() {
int receive = 0;
try {
while ((receive = in.read()) != -1) {
//讀取內(nèi)存中的數(shù)據(jù), 并打印
System.out.print((char) receive);
}
} catch (IOException e) {}
}
}
private static class Inputer implements Runnable {
//輸出流
private PipedWriter out = new PipedWriter();
@Override
public void run() {
int receive = 0;
try {
while ((receive = System.in.read()) != -1) {
//讀取console的輸入,輸出到內(nèi)存中
out.write(receive);
}
} catch (IOException e) {}
}
}
}
在控制臺輸入 hello, world! 然后回車, 運行結(jié)果如下:
hello, world!
hello, world!
3.3 Thread.join
如果一個線程threadA執(zhí)行了threadB.join()語句, 那么threadA會等到線程threadB執(zhí)行中止之后, 才從threadB.join()返回, 繼續(xù)執(zhí)行threadA的代碼
下面的代碼通過join()方法, 讓10個線程按順序執(zhí)行
public class ThreadJoinExample {
public static void main(String[] args) {
Thread pre = new Thread(new OrderThread(null), "thread0");
pre.start();
for (int i = 1; i < 10; i++) {
Thread thread = new Thread(new OrderThread(pre), "thread" + i);
thread.start();
pre = thread;
}
}
// 按順序執(zhí)行的線程
static class OrderThread implements Runnable {
// 上一個線程
private Thread pre;
public OrderThread(Thread pre) {
this.pre = pre;
}
@Override
public void run() {
if (pre == null) return;
try {
pre.join();
} catch (InterruptedException e) {}
System.out.println("after " + pre.getName() + " join, "
+ Thread.currentThread().getName() + " terminate.");
}
}
}
運行結(jié)果:
after thread0 join, thread1 terminate.
after thread1 join, thread2 terminate.
after thread2 join, thread3 terminate.
after thread3 join, thread4 terminate.
after thread4 join, thread5 terminate.
after thread5 join, thread6 terminate.
after thread6 join, thread7 terminate.
after thread7 join, thread8 terminate.
after thread8 join, thread9 terminate.
結(jié)果分析:
每個線程終止的前提就是前驅(qū)線程的終止, 每個線程等待前驅(qū)線程終止后, 才從join()方法返回
實現(xiàn)原理:
Thread類的join方法就是通過wait方法實現(xiàn)的
public final synchronized void join(long millis){
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {}
}
線程threadA調(diào)用join()方法, 相當于threadA調(diào)用了wait()方法, 那么主線程threadMain就會進入waiting狀態(tài), 等待threadA執(zhí)行結(jié)束, 調(diào)用自身的notifyAll()方法, 通知所有等待在threadA的線程
3.4 ThreadLocal
線程本地變量, 是一個以ThreadLocal為鍵, 任意對象為值的存儲結(jié)構(gòu), 線程可以通過ThreadLocal對象, 查詢或者設置綁定在這個線程上的值
ThreadLocal有一個內(nèi)部類ThreadLocalMap, ThreadLocalMap內(nèi)部有一個內(nèi)部類Entry, Entry以ThreadLocal為key, Object為value
ThreadLocal#get()方法執(zhí)行步驟
- 先獲取當前線程
- 獲取當前線程綁定的值(ThreadLocalMap)
- 如果Map不為空, 那么獲取當前ThreadLocal對應的entry
- 如果Map為空, 那么初始化值
- 設置線程綁定的值, 方法類似
//ThreadLocal源碼
public class ThreadLocal<T> {
//獲取ThreadLocal中保存的元素
public T get() {
//獲取當前線程
Thread t = Thread.currentThread();
//獲取線程對應的Map
ThreadLocalMap map = getMap(t);
if (map != null) {
//獲取當前ThreadLocal對應的entry
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
//獲取并返回值
T result = (T)e.value;
return result;
}
}
//初始化并返回值
return setInitialValue();
}
//初始化并返回值
private T setInitialValue() {
//初始化值, 默認為null
T value = initialValue();
//獲取當前線程
Thread t = Thread.currentThread();
//獲取當前線程t的threadLocals
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
//如果Map為空,那么創(chuàng)建map
createMap(t, value);
return value;
}
void createMap(Thread t, T firstValue) {
//實例化當前線程的threadLocals
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
//ThreadLocalMap靜態(tài)內(nèi)部類
static class ThreadLocalMap {
//Entry靜態(tài)內(nèi)部類
static class Entry extends WeakReference<ThreadLocal<?>> {
//和ThreadLocal綁定的元素
Object value;
//ThreadLocal為key
//任意Object為value
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
}
}
4. 線程池
服務端程序, 經(jīng)常面對的是客戶端傳入執(zhí)行時間短, 工作內(nèi)容較為單一的任務, 需要服務端快速處理并返回結(jié)果
如果服務端每次接收到一個任務, 就創(chuàng)建一個線程, 那么可能會創(chuàng)建很多線程, 耗盡CPU資源, 這會使操作系統(tǒng)頻繁的進行上下文切換, 增加系統(tǒng)負載, 而且線程的創(chuàng)建和消亡都要耗費系統(tǒng)資源
線程池很好的解決了這個問題, 預先創(chuàng)建若干數(shù)量的線程, 并重復使用這些固定數(shù)目的線程來完成任務的執(zhí)行