把java基礎擼一邊,從簡單的開始
學習多執行緒,首先要了解多執行緒。有很多概念還是要了解一下
對“程”的基本認識
推薦連結:執行緒和程式的區別,很詳細(如果這個看了,下面的幾段文字可以過,抄的)
有兩種程,程式和執行緒
程式,是併發執行的程式在執行過程中分配和管理資源的基本單位,是一個動態概念,競爭計算機系統資源的基本單位。
執行緒,執行緒是程式的一部分,一個沒有執行緒的程式可以被看作是單執行緒。執行緒有時又被成為輕量級程式,也是CPU排程的一個基本單位
執行緒的改變只代表CPU的執行過程的改變,而沒有發生程式所擁有的資源變化。除了CPU之外,計算機的軟硬體資源分配與執行緒無關,執行緒只能共享它所屬程式的資源。
與程式控制表和PCB相似,每個執行緒也有自己的執行緒控制表TCB,而這個TCB中所儲存的執行緒狀態則比PCB表少得多,這些資訊主要是相關指標用堆疊(系統棧和使用者棧),暫存器中的狀態資料。
程式擁有一個完整的虛擬機器地址空間,不依賴於執行緒而獨立存在;反之,執行緒是程式的一部分,沒有自己的地址空間,與程式內的其他執行緒一起共享給該程式的所有資源。
java執行緒生命週期圖(這圖是我照著畫的):
如果有興趣的話,也可以畫畫。
以下是我亂逼逼,自己的認識。最好看官方的
執行緒的生命狀態:新建狀態,就緒狀態,執行狀態,阻塞狀態,死亡狀態
阻塞狀態的時候,有兩個定義,等待,和堵塞。等待:(理解)執行緒要進入的CPU被其他執行緒佔用,服務執行該執行緒的任務。阻塞狀態,程式碼notify()方法,或者說,除系統通知外叫醒這個執行緒的是等待。而堵塞是系統叫醒,比如sleep()。睡眠玩時間之後,系統會通知這個執行緒結束了。
Thread物件例項化後執行start()方法並沒有馬上去執行run()方法,而是在在Runnable就緒狀態去搶奪CPU資源開始執行。起跑100米也要準備以下start()後就是需要準的強制CPU資源的那一瞬間,到了Running執行狀態後如果執行完畢或者有異常退出,這個執行緒也就執行完畢Dead死亡了。
但還有可能在執行過程中出現堵塞狀況,比如sleep()睡眠,join()方法就會出現堵塞,當sleep結束或者join終端,I/O完成的時候會重新到Runnable準備去搶佔CPU資源,而正在執行的Running的執行緒在yield的時候就與禮讓CPU資源 進入Runnable狀態
在Running狀態的時候synchronize會進入鎖,這個時候會等待處理一下。當同步鎖被釋放的時候會進入Runnable再去搶佔資源
在Running狀態的時候synchronize狀態後wait()釋放鎖等待再到notify()喚醒鎖,再次走當上面剛剛說的堵塞中。這裡就基本瞭解了執行緒的執行狀態
這是上面我推薦的部落格上面的
簡單看一下原始碼
下面是基本的使用,執行緒有兩個中重要的類,一個是抽象類,Runnable,一個是Runnable實現類Thread。使用執行緒的時候一般是new Thread().start();這樣就可以開啟一個執行緒
還有就是實現Runnable的類,比如A實現了Runnable類,
A a = new A;
new Thread(a).start();這樣也可以開啟一個執行緒。兩者的實現不同來自於對Thread類不同的構造方法不同
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}複製程式碼
在來看看Runnable類
public interface Runnable {
public abstract void run();
}複製程式碼
run()方法裡面就是這個執行緒的執行內容。
再來看看Thread的start()方法
public synchronized void start() {
if (threadStatus != 0)
throw new IllegalThreadStateException();
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
}
private native void start0();複製程式碼
看到native就知道是去呼叫C程式碼
start0()方法會新執行一個執行緒,新執行緒會呼叫run()方法。
public void run() {
if (target != null) {
target.run();
}
}複製程式碼
這樣一來就可以理清楚繼承Thread類和實現Runnable類兩種基本用法的區別
通過繼承Thread類的需要去實現Thread。因為在構建方法中init方法是傳遞的null去賦值的。如果是建立傳遞了Runnable中,是傳遞過去。並且賦值,這樣再run()方法中判斷了target()並且執行了該實現Runnable類的run()方法
基本實現
知道這個程式碼背景,就對執行緒的使用有了一個概念。
public class Demo1 extends Thread{
public Demo1(String name){
super(name);
}
@Override
public void run() {
while (!interrupted()) {
System.out.println("執行緒 :"+getName());
}
}
public static void main(String[] age){
Demo1 a = new Demo1("A");
a.start();
}
}複製程式碼
繼承Thread的實現
public class Demo2 implements Runnable {
public static void main(String[] age){
Demo2 demo2 = new Demo2();
Thread thread = new Thread(demo2);
thread.start();
}
public void run(){
while (true){
System.out.println("thread running ...");
}
}
}複製程式碼
實現抽象類的Runnable