多線程:
概述: 進程有多條執行路徑, 合成爲: 多線程.
進程: 可執行程序(文件), 例如: .exe
//可以把進程理解爲一輛車.
線程: 進程的執行路徑(執行單元)
//可以把線程理解爲: 是馬路
記憶:
1. 一臺電腦上可以有多個進程, 這些進程之間的數據是相互隔離的.
//例如: qq.exe, 飛秋.exe
2. 一個進程可以有多條線程, 這些線程可以共享該進程的數據.
//例如: 往QQ羣共享放一個文件, 該羣中的所有的用戶都可以下載.
多線程並行和併發的區別是什麼:
並行: 兩個(多個)線程同時執行. //前提: 需要多核CPU
併發:
兩個(多個)線程同時請求執行, 但是CPU同一瞬間只能執行一個線程,
於是就安排這些線程交替執行, 因爲時間間隔非常短, 我們看起來好像是同時執行的, 其實不是.
多線程的實現方式:
方式一: 繼承Thread類.
步驟:
1) 定義一個類(MyThread), 繼承Thread類.
2) 重寫Thread#run().
//重寫Thread類中的run()方法.
3) 把要執行的代碼放入run()方法中.
4) 在測試類中,創建線程對象.
5) 開啓線程. //start()
注意事項:
A: 如果調用run()方法, 只是普通的方法調用.
B: 開啓線程必須調用start()方法, 該方法會自動去調用run()方法.
C: 同一線程不能重複開啓, 否則會報: IllegalThreadStateException異常.
方式二: 實現Runnable接口.
步驟:
1) 定義一個類(MyRunnable), 實現Runnable接口.
2) 重寫Runnable#run().
3) 把要執行的代碼放入run()方法中.
4) 在測試類中, 創建Runnable接口的子類對象,
MyRunnable mr = new MyRunnable();
並將其作爲參數傳入Thread類的構造, 創建線程對象.
Thread th = new Thread(mr);
5) 開啓線程. //start()
方式三: 結合線程池使用(實現Callable接口). //暫時瞭解即可.
多線程的執行特點是什麼:
隨機性, 延遲性.
因爲CPU在做着高效的切換.
多線程案例: 模擬賣票.
//需求: 四個窗口, 賣100張票.
出現的問題:
出現負數:if條件
出現重複值:ticket--
解決方案:
採用 同步代碼塊解決.
Thread類中的成員:
構造方法:
public Thread();
public Thread(String name);
public Thread(Runnable target);
public Thread(Runnable target,String name);
成員方法:
run(); //裏邊定義的是線程要執行的代碼, 該方法會自動被start()方法調用.
start(); //開啓線程, 會自動調用run().
getName();
setName();
sleep(); //休眠線程, 單位是: 毫秒.
currentThread(); //獲取當前正在執行的線程對象(的引用).
同步:
概述/作用:
多線程(環境) 併發 操作同一數據, 有可能引發安全問題, 就需要用到同步解決.
分類:
同步代碼塊:
格式:
synchronized(鎖對象) {
//要加鎖的代碼
}
鎖對象:
1) 同步代碼塊的鎖對象可以是任意類型的對象.
2) 必須使用同一把鎖, 否則可能出現鎖不住的情況.
同步方法:
靜態方法:
鎖對象: 該類的字節碼文件對象.
非靜態方法:
鎖對象: this
多線程的難點(一般只在面試的時候用, 工作中基本不用)
死鎖:
死鎖是指兩個或兩個以上的進程在執行過程中,由於競爭資源或者由於彼此通信而造成的
一種阻塞的現象,若無外力作用,它們都將無法推進下去。
多線程的生命週期:
新建, 就緒, 運行(有可能發生阻塞和等待), 死亡.
擴展的知識:
1) 匿名內部類: //本質是一個對象. //記憶&掌握
內部類:
概述: 類裏邊還有一個類, 裏邊那個類叫內部類, 外邊那個類叫外部類.
分類:
成員內部類: 定義在成員位置的內部類.
局部內部類: 定義在局部位置的內部類.
概述:
就是沒有名字的 局部內部類.
格式:
new 類名或者接口名(){
//重寫類或者接口中 所有的 抽象方法;
};
本質:
專業版: 就是一個繼承了類或者實現了接口的 匿名的子類對象.
大白話: 匿名內部類不是類, 而是子類對象.
匿名內部類在實際開發中的應用:
1) 當對 對象方法(成員方法) 僅調用一次的時候.
2) 可以作爲方法的實參進行傳遞.
個人建議:
當接口中或者抽象類中的 抽象方法僅有一個的時候, 就可以 考慮使用匿名內部類.
2) 實現Runnable接口的原理. //多態.
背景:
多線程的第一種實現方式是: 繼承Thread類, 因爲我們自定義的類(MyThread)是Thread類的子類,
所以MyThread類的對象調用start()方法的時候, 自動調用MyThread#run(), 這個我們可以理解,
但是MyRunnable類是實現了Runnable接口, 而Runnable接口的run()方法和Thread#start()沒有關係,
問: 爲什麼Thread#start(), 會自動調用Runnable接口的子類(MyRunnable)中的 run()方法呢?
簡化版的源碼:
測試類中的代碼
public static void main(String[] args) {
MyRunnable mr = new MyRunnable();
Thread th = new Thread(mr);
th.start(); //問: 爲什麼會自動調用 MyRunnable#run();
}
public class Thread {
private Runnable target; //new MyRunnable();
public Thread(Runnable target) { //new MyRunnable();
this.target = target;
}
public void run() {
if(target != null) {
target.run(); //new MyRunnable().run();
}
}
}
從Eclipse貼過來的源碼:
public class Thread {
private Runnable target;
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
init(g, target, name, stackSize, null);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc) {
this.target = target;
}
@Override
public void run() {
if (target != null) {
target.run();
}
}
}
java基礎之多線程
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.