Java 多執行緒(一)—— 概念的引入
併發和並行
程序和執行緒
如何建立多執行緒
第一種方法:繼承 Thread 類
第二種方法:實現 Runnable 介面
第三種方法:使用匿名內部類建立執行緒
正文
回到頂部
併發和並行
並行:指兩個或多個時間在同一時刻發生(同時發生);
併發:指兩個或多個事件在一個時間段內發生。
在作業系統中,安裝了多個程式,併發指的是在一段時間內巨集觀上有多個程式同時執行,這在單 CPU 系統中,每一時刻只能有一道程式執行,即微觀上這些程式是分時的交替執行,只不過是給人的感覺是同時執行,那是因為分時交替執行的時間是非常短的。
而在多個 CPU 系統中,則這些可以併發執行的程式便可以分配到多個處理器上(CPU),實現多工並行執行,即利用每個處理器來處理一個可以併發執行的程式,這樣多個程式便可以同時執行。
目前電腦市場上說的多核 CPU,便是多核處理器,核 越多,並行處理的程式越多,能大大的提高電腦執行的效率。
注意:單核處理器的計算機肯定不能並行的處理多個任務,只能是多個任務交替的在單個 CPU 上執行。
回到頂部
程序和執行緒
程序:是指一個記憶體中執行的應用程式,每個程序都有一個獨立的記憶體空間,一個應用程式可以同時執行多個程序;程序也是程式的一次執行過程,是系統執行程式的基本單位;系統執行一個程式即是一個程序從建立、執行到消亡的過程。
執行緒:程序內部的一個獨立執行單元;一個程序可以同時併發的執行多個執行緒,可以理解為一個程序便相當於一個單 CPU 作業系統,而執行緒便是這個系統中執行的多個任務。
注意:1、因為一個程序中的多個執行緒是併發執行的,那麼從微觀角度看也是有先後順序的,哪個執行緒執行完全取決於 CPU 的排程,程式設計師是干涉不了的。而這也就造成的多執行緒的隨機性。
2、Java 程式的程序裡面至少包含兩個執行緒,主程序也就是 main()方法執行緒,另外一個是垃圾回收機制執行緒。每當使用 java 命令執行一個類時,實際上都會啟動一個 JVM,每一個 JVM 實際上就是在作業系統中啟動了一個執行緒,java 本身具備了垃圾的收集機制,所以在 Java 執行時至少會啟動兩個執行緒。
3、由於建立一個執行緒的開銷比建立一個程序的開銷小的多,那麼我們在開發多工執行的時候,通常考慮建立多執行緒,而不是建立多程序。
4、多執行緒是為了同步完成多個任務,不是為了提高程式執行效率,而是通過提高資源使用效率來提高系統的效率。比如做一個新增功能,需要向很多使用者傳送簡訊和郵件,如果需要一分鐘,不能能讓使用者等一分鐘才響應,可以使用多執行緒做後臺傳送,如果是單核,則多個任務交替的在單個 CPU 上執行,理論上比不使用多執行緒耗時多,因為CPU切換任務需要耗費時間,如果是多核,則可以提高資源的使用效率,多核可以充分利用上。
回到頂部
如何建立多執行緒
第一種方法:繼承 Thread 類
步驟:1、定義一個執行緒類 A 繼承於 java.lang.Thread 類
2、在 A 類中覆蓋 Thread 類的 run() 方法
3、在 run() 方法中編寫需要執行的操作
4、在 main 方法(執行緒)中,建立執行緒物件,並啟動執行緒
建立執行緒類:A類 a = new A()類;
呼叫 start() 方法啟動執行緒:a.start();
複製程式碼
/**
* @author: ChenHao
* 建立多執行緒的第一種方式,繼承java.lang.Thread類
* @Description:建立一個子執行緒,完成1-100之間自然數的輸出。同樣,主執行緒執行同樣的操作
* @Date: Created in 10:50 2018/10/29
*/
public class TestThread {
public static void main(String [] args){
SubThread subThread1=new SubThread();
SubThread subThread2=new SubThread();
//呼叫執行緒的start(),啟動此執行緒;呼叫相應的run()方法
subThread1.start();
subThread2.start();
//一個執行緒只能夠執行一次start(),start()中會判斷threadStatus的狀態是否為0,不為0則丟擲異常
//subThread1.start();
//不能通過Thread實現類物件的run()去啟動一個執行緒,此時只是主執行緒呼叫方法而已,並沒有啟動執行緒
//subThread1.run();
for (int i=0;i<=100;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
//1.建立一個繼承Thread的子類
class SubThread extends Thread{
//2.重寫run方法,方法內實現此子執行緒要完成的功能
@Override
public void run(www.fengshen157.com){
for (int i=0;i<=100;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
複製程式碼
注意:1、不能通過Thread實現類物件的run()去啟動一個執行緒,此時只是主執行緒呼叫方法而已,並沒有啟動執行緒,要啟動執行緒,必須通過Start()方法
2、一個執行緒只能夠執行一次start(),start()中會判斷threadStatus的狀態是否為0,不為0則丟擲異常,所以一個執行緒呼叫兩次start()會報異常
第二種方法:實現 Runnable 介面
1、Runnable介面應由任何類實現,其例項將由執行緒執行。 該類必須定義一個無引數的方法,稱為run 。
2、該介面旨在為希望在活動時執行程式碼的物件提供一個通用協議。此類整個只有一個 run() 抽象方法
步驟:1、定義一個執行緒類 A 實現於 java.lang.Runnable 介面(注意:A類不是執行緒類,沒有 start()方法,不能直接 new A 的例項啟動執行緒)
2、在 A 類中覆蓋 Runnable 介面的 run() 方法
3、在 run() 方法中編寫需要執行的操作
4、在 main 方法(執行緒)中,建立執行緒物件,並啟動執行緒
建立執行緒類:Thread t = new Thread( new A類() ) ;
呼叫 start() 方法啟動執行緒:t.start();
複製程式碼
package main.java.Thread;
/**
* @author: ChenHao
* @Description:建立多執行緒的方式二:實現runnable
* 對比一下繼承的方式 VS 實現的方式
* 哪個方式好?實現的方式優於繼承的方式
* why? ①避免java單繼承的侷限性
* ②如果多個執行緒要操作同一份資源,更適合使用實現的方式
* @Date: Created in 10:50 2018/10/29
*/
public class TestThread2 {
public static void main(String [] args){
//此程式存線上程的安全問題,列印車票時,會出現重票、錯票,後面執行緒同步會講到
Window window=new Window(www.chaoyueyule.net);
Thread thread1=new Thread(window,"視窗一");
Thread thread2=new Thread(window,"視窗二");
Thread thread3=new Thread(window,"視窗三");
thread1.start(www.yinmaoyule178.com );
thread2.start();
thread3.start();
}
}
class Window implements Runnable{
int ticket=100;
@Override
public void run(){
while (true){
if(ticket > 0){
try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"售票,票號為:"+ticket--);
}else {
break;
}
}
}
}
複製程式碼
哪個方式好?實現的方式優於繼承的方式
why? ①避免java單繼承的侷限性
②如果多個執行緒要操作同一份資源,更適合使用實現的方式
注意:此程式存線上程的安全問題,列印車票時,會出現重票、錯票
第三種方法:使用匿名內部類建立執行緒
複製程式碼
public static void main(String[www.dfgjpt.com/ ] args) {
for(int i = 0 ; i < 10 ; i++){
System.out.println("玩遊戲"+i);
if(i==5){
new Thread(new Runnable() {
@Override
public void run(www.ysyl157.com) {
for(int i = 0 ; i < 10 ;i++){
System.out.println("播放音樂"+i);
}
}
}).start();
}
}
}