1 繼承Thread類

2 實(shí)現(xiàn)Runnable接口

a.常規(guī)使用
// 步驟1:創(chuàng)建線程輔助類,實(shí)現(xiàn)Runnable接口
class MyThread implements Runnable{
....
@Override
// 步驟2:復(fù)寫run(),定義線程行為
public void run(){
}
}
// 步驟3:創(chuàng)建線程輔助對象,即 實(shí)例化 線程輔助類
MyThread mt=new MyThread();
// 步驟4:創(chuàng)建線程對象,即 實(shí)例化線程類;線程類 = Thread類;
// 創(chuàng)建時通過Thread類的構(gòu)造函數(shù)傳入線程輔助類對象
// 原因:Runnable接口并沒有任何對線程的支持,我們必須創(chuàng)建線程類(Thread類)的實(shí)例,從Thread類的一個實(shí)例內(nèi)部運(yùn)行
Thread td=new Thread(mt);
// 步驟5:通過 線程對象 控制線程的狀態(tài),如 運(yùn)行、睡眠、掛起 / 停止
// 當(dāng)調(diào)用start()方法時,線程對象會自動回調(diào)線程輔助類對象的run(),從而實(shí)現(xiàn)線程操作
td.start();
b.匿名類
// 步驟1:通過匿名類 直接 創(chuàng)建線程輔助對象,即 實(shí)例化 線程輔助類
Runnable mt = new Runnable() {
// 步驟2:復(fù)寫run(),定義線程行為
@Override
public void run() {
}
};
// 步驟3:創(chuàng)建線程對象,即 實(shí)例化線程類;線程類 = Thread類;
Thread mt1 = new Thread(mt, "窗口1");
// 步驟4:通過 線程對象 控制線程的狀態(tài),如 運(yùn)行、睡眠、掛起 / 停止
mt1.start();
2.1 Thread和Runnable的區(qū)別

3 Handler


3.1 Handler工作原理
工作流程
1.異步通信準(zhǔn)備
2.消息發(fā)送
3.消息循環(huán)
4.消息處理

3.2 工作流程


3.3 使用Handler.sendMessage()
class mHandler extends Handler {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
}
}
void useHandler() {
Handler mHandler = new mHandler();
Message message = Message.obtain();
message.what = 1;
message.obj = "AA";
mHandler.sendMessage(message);
}
3.4 使用Handler.post
void useHandler() {
Handler mHandler = new mHandler();
mHandler.post(new Runnable() {
@Override
public void run() {
}
});
}
3.5 具體類

4 AsyncTask
屬于抽象類 使用時要實(shí)現(xiàn)子類
4.1 作用
1 實(shí)現(xiàn)多線程
在工作線程中執(zhí)行任務(wù)
2 異步通信 消息傳遞
實(shí)現(xiàn)工作線程和主線程直接的通信
4.2 優(yōu)點(diǎn)
- 方便實(shí)現(xiàn)異步通信
不需要使用 "任務(wù)線程 + Handler" 的復(fù)雜組合 - 節(jié)省資源
采用線程池的緩存線程 + 復(fù)用線程 避免了頻繁創(chuàng)建和銷毀線程所帶來的系統(tǒng)資源開銷
4.3 類和方法
4.3.1 類定義
public abstract class AsyncTask<Params, Progress, Result> {
...
}
// 類中參數(shù)為3種泛型類型
// 整體作用:控制AsyncTask子類執(zhí)行線程任務(wù)時各個階段的返回類型
// 具體說明:
// a. Params:開始異步任務(wù)執(zhí)行時傳入的參數(shù)類型,對應(yīng)excute()中傳遞的參數(shù)
// b. Progress:異步任務(wù)執(zhí)行過程中,返回下載進(jìn)度值的類型
// c. Result:異步任務(wù)執(zhí)行完成后,返回的結(jié)果類型,與doInBackground()的返回值類型保持一致
// 注:
// a. 使用時并不是所有類型都被使用
// b. 若無被使用,可用java.lang.Void類型代替
// c. 若有不同業(yè)務(wù),需額外再寫1個AsyncTask的子類
}
4.3.2 核心方法

-
方法執(zhí)行順序
image.png
4.4 使用步驟
- 創(chuàng)建AsyncTask 子類 和 根據(jù)需求實(shí)現(xiàn)核心方法
2 創(chuàng)建AsyncTask 子類的實(shí)例對象
3 手動調(diào)用execute() 從而執(zhí)行異步線程任務(wù)
public class MyTask extends AsyncTask<String, Integer, String> {
//執(zhí)行線程前的操作
@Override
protected void onPreExecute() {
super.onPreExecute();
}
//接受輸入?yún)?shù) 執(zhí)行任務(wù)中的耗時操作 返回線程任務(wù)執(zhí)行的結(jié)果
@Override
protected String doInBackground(String... strings) {
return null;
}
//在主線程 顯示線程任務(wù)執(zhí)行的進(jìn)度
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
}
//接受線程任務(wù)執(zhí)行結(jié)果 將執(zhí)行結(jié)果顯示到UI組件
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
}
//將異步任務(wù)設(shè)置為取消狀態(tài)
@Override
protected void onCancelled() {
super.onCancelled();
}
}
4.5 生命周期
AsyncTask 不與任何組件綁定聲明周期
在Activity 或 Fragment中使用 AsyncTask時,最好在Activity 或 Fragment的onDestory()調(diào)用 cancel(boolean)
4.6 內(nèi)存泄露
若AsyncTask被聲明為Activity的非靜態(tài)內(nèi)部類,當(dāng)Activity需銷毀時,會因AsyncTask保留對Activity的引用 而導(dǎo)致Activity無法被回收,最終引起內(nèi)存泄露
把AsyncTask聲明為Activity的靜態(tài)內(nèi)部類
4.7 線程任務(wù)執(zhí)行結(jié)果 丟失
當(dāng)Activity重新創(chuàng)建時(屏幕旋轉(zhuǎn) / Activity被意外銷毀時后恢復(fù)),之前運(yùn)行的AsyncTask(非靜態(tài)的內(nèi)部類)持有的之前Activity引用已無效,故復(fù)寫的onPostExecute()將不生效,即無法更新UI操作
在Activity恢復(fù)時的對應(yīng)方法 重啟 任務(wù)線程
4.8 工作原理
AsyncTask的實(shí)現(xiàn)原理 = 線程池 + Handler

5. ThreadPool


5.1 內(nèi)部原理邏輯

5.2 常見的4類功能線程池
- 定長線程池(FixedThreadPool)
- 定時線程池(ScheduledThreadPool )
- 可緩存線程池(CachedThreadPool)
- 單線程化線程池(SingleThreadExecutor)
5.2.1 定長線程池
只有核心線程 不會被回收 線程數(shù)量固定 任務(wù)隊列無大小限制(超出的線程任務(wù)會在隊列中等待)
應(yīng)用場景:控制線程最大并發(fā)數(shù)
//創(chuàng)建定長線程池對象 設(shè)置線程池數(shù)量固定為3
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
//創(chuàng)建好Runnable
Runnable task = new Runnable() {
@Override
public void run() {
System.out.println("執(zhí)行任務(wù)");
}
};
// 向線程池提交任務(wù)
fixedThreadPool.execute(task);
// 關(guān)閉線程池
fixedThreadPool.shutdown();
5.2.2 定時線程池
核心線程數(shù)量固定、非核心線程數(shù)量無限制(閑置時馬上回收)
執(zhí)行定時 / 周期性 任務(wù)
// 1. 創(chuàng)建 定時線程池對象 & 設(shè)置線程池線程數(shù)量固定為5
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
//創(chuàng)建好Runnable
Runnable task = new Runnable() {
@Override
public void run() {
System.out.println("執(zhí)行任務(wù)");
}
};
// 向線程池提交任務(wù)
scheduledExecutorService.schedule(task,1, TimeUnit.SECONDS);// 延遲1s后執(zhí)行任務(wù)
//延遲10毫秒 每隔1000毫秒執(zhí)行任務(wù)
scheduledExecutorService.scheduleAtFixedRate(task,10,1000,TimeUnit.MILLISECONDS);
//關(guān)閉線程
scheduledExecutorService.shutdown();
5.2.3 可緩存線程池
只有非核心線程,線程數(shù)量不固定(可無限大),靈活回收空閑線程(具備超時機(jī)制,全部回收時幾乎不占系統(tǒng)資源),新建線程(無限城可用時)
任何線程任務(wù)到來都會立刻執(zhí)行,不需要等待
執(zhí)行大量、耗時少的線程任務(wù)
// 1. 創(chuàng)建可緩存線程池對象
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
// 2. 創(chuàng)建好Runnable類線程對象 & 需執(zhí)行的任務(wù)
Runnable task =new Runnable(){
public void run(){
System.out.println("執(zhí)行任務(wù)啦");
}
};
// 3. 向線程池提交任務(wù):execute()
cachedThreadPool.execute(task);
// 4. 關(guān)閉線程池
cachedThreadPool.shutdown();
//當(dāng)執(zhí)行第二個任務(wù)時第一個任務(wù)已經(jīng)完成
//那么會復(fù)用執(zhí)行第一個任務(wù)的線程,而不用每次新建線程。
5.2.4 單線程化線程池
只有一個核心線程(保證所有任務(wù)按照指定順序在一個線程中執(zhí)行,不需要處理線程同步的問題)
不適合并發(fā)但可能引起IO阻塞及影響UI線程的操作
// 1. 創(chuàng)建單線程化線程池
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
// 2. 創(chuàng)建好Runnable類線程對象 & 需執(zhí)行的任務(wù)
Runnable task =new Runnable(){
public void run(){
System.out.println("執(zhí)行任務(wù)啦");
}
};
// 3. 向線程池提交任務(wù):execute()
singleThreadExecutor.execute(task);
// 4. 關(guān)閉線程池
singleThreadExecutor.shutdown();
5.3 線程池對比

5.4 多線程對比

6. Synchronized關(guān)鍵字

6.1 原理
- 依賴JVM實(shí)現(xiàn)同步
2.底層通過一個監(jiān)視器對象(monitor)完成,wait() notify() 等方法也依賴于monitor對象
監(jiān)視器鎖(monitor)的本質(zhì) 依賴于 底層操作系統(tǒng)的互斥鎖(Mutex Lock)實(shí)現(xiàn)
6.2 鎖的類型和等級

6.2.1 區(qū)別

6.3 使用規(guī)則

//對象鎖
class Test {
//方法鎖
public synchronized void Method1() {
System.out.println("我是對象鎖也是方法鎖");
try {
Thread.sleep(500);
}catch (InterruptedException e) {
e.printStackTrace();
}
}
//代碼塊形式
public void Method2() {
synchronized (this) {
System.out.println("我是對象鎖");
try {
Thread.sleep(500);
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//方法鎖
public synchronized void Method1() {
System.out.println("我是對象鎖也是方法鎖");
try {
Thread.sleep(500);
}catch (InterruptedException e) {
e.printStackTrace();
}
}
//類鎖
class Test {
//鎖靜態(tài)方法
public static synchronized void Method1() {
System.out.println("我是對象鎖也是方法鎖");
try {
Thread.sleep(500);
}catch (InterruptedException e) {
e.printStackTrace();
}
}
//鎖靜態(tài)代碼塊
public void Method2() {
synchronized (Test.class){
System.out.println("我是類鎖二號");
try{
Thread.sleep(500);
} catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
6.4 特別注意
若使用synchronized 關(guān)鍵字修飾線程類的run() 由于run()在線程的整個生命周期內(nèi)一直在運(yùn)行,因此將會導(dǎo)致它對本類恩和synchronized 方法的調(diào)用都永遠(yuǎn)不會成功
- 解決方案
使用 Synchronized關(guān)鍵字聲明代碼塊
synchronized(syncObject) {
// 訪問或修改被鎖保護(hù)的共享狀態(tài)
// 上述方法 必須 獲得對象 syncObject(類實(shí)例或類)的鎖
}
6.5 特點(diǎn)

7. ThreadLocal

7.1 使用流程
7.1.1 創(chuàng)建ThreadLocal變量
//1.直接創(chuàng)建對象
private ThreadLocal myThreadLocal = new ThreadLocal();
//2.創(chuàng)建泛型對象
private ThreadLocal threadLocal = new ThreadLocal<String>();
//3.創(chuàng)建泛型對象 & 初始化值
//指定泛型的好處 不需要每次對使用get()方法返回的值作強(qiáng)制類型轉(zhuǎn)換
private ThreadLocal local = new ThreadLocal<String>() {
@Nullable
@Override
protected String initialValue() {
return "This is the initial value";
}
};
1.ThreadLocal 實(shí)例 = 類中的private static字段
2.只需實(shí)例化對象一次 & 不需要知道它是被哪個線程實(shí)例化
3.每個線程都保持 對其他線程局部變量副本的隱式引用
4.線程消失后 其線程舉報變量實(shí)例的所有副本都會被垃圾回收(除非存在對這些副本的其他引用)
5.雖然所有的線程都能訪問到這個ThreadLocal實(shí)例 但是每個線程只能訪問到自己通過調(diào)研ThreadLocal的set()設(shè)置的值(哪怕2個不同的線程在同一個ThreadLocal對象上設(shè)置了不同的值,他們?nèi)匀粺o法訪問到對方的值)
7.1.2 訪問ThreadLocal變量
// 1. 設(shè)置值:set()
// 需要傳入一個Object類型的參數(shù)
myThreadLocal.set("初始值”);
// 2. 讀取ThreadLocal變量中的值:get()
// 返回一個Object對象
String threadLocalValue = (String) myThreadLocal.get();
7.2 具體使用
class ThreadLocalTest {
public static void main(String[] args) {
MyRunnable runnable = new MyRunnable();
new Thread(runnable,"線程1").start();
new Thread(runnable,"線程2").start();
}
public static class MyRunnable implements Runnable {
private ThreadLocal<String> threadLocal = new ThreadLocal<>() {
@Nullable
@Override
protected Object initialValue() {
return "初始化值";
}
};
@Override
public void run() {
//運(yùn)行線程時 分別設(shè)置 & 獲取ThreadLocal的值
String name = Thread.currentThread().getName();
threadLocal.set(name + "的threadLocal");
try {
Thread.sleep(1000);
}catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name + ":" + threadLocal.get());
}
}
}
7.3 實(shí)現(xiàn)原理
ThreadLocal類中有1個Map(稱:ThreadLocalMap):用于存儲每個線程 & 該線程設(shè)置的存儲在ThreadLocal變量的值
1.ThreadLocalMap的鍵key = 當(dāng)前ThreadLocal實(shí)例、值value = 該線程設(shè)置的存儲在ThreadLocal變量的值
2.該key是 ThreadLocal對象的弱引用;當(dāng)要拋棄掉ThreadLocal對象時,垃圾收集器會忽略該 key的引用而清理掉ThreadLocal對象
7.4 與同步機(jī)制的區(qū)別

