JAVA之多執行緒
一、多執行緒介紹
1、程序:程序指正在執行的程式。確切的來說,當一個程式進入記憶體執行,即變成一個程序,程序是處於執行過程中的程式,並且具有一定獨立功能。
2、執行緒:執行緒是程序中的一個執行單元,負責當前程序中程式的執行,一個程序中至少有一個執行緒。一個程序中是可以有多個執行緒的,這個應用程式也可以稱之為多執行緒程式。
簡而言之:一個程式執行後至少有一個程序,一個程序中可以包含多個執行緒
3、程式執行原理:
分時排程
所有執行緒輪流使用 CPU 的使用權,平均分配每個執行緒佔用 CPU 的時間。
搶佔式排程
優先讓優先順序高的執行緒使用 CPU,如果執行緒的優先順序相同,那麼會隨機選擇一個(執行緒隨機性),Java使用的為搶佔式排程。
4、主執行緒:jvm啟動後,必然有一個執行路徑(執行緒)從main方法開始的,一直執行到main方法結束,這個執行緒在java中稱之為主執行緒。
當程式的主執行緒執行時,如果遇到了迴圈而導致程式在指定位置停留時間過長,則無法馬上執行下面的程式,需要等待迴圈結束後能夠執行。
二、建立執行緒的方式
1、繼承Thread類
1)繼承Thread類:因為Thread類用來描述執行緒,具備執行緒應該有功能。那為什麼不直接建立Thread類的物件呢?如下程式碼:
Thread t1 = new Thread(); t1.start();//這樣做沒有錯,但是該start呼叫的是Thread類中的run方法,而這個run方法沒有做什麼事情,更重要的是這個run方法中並沒有定義我們需要讓執行緒執行的程式碼。
2)建立執行緒的目的是什麼?
是為了建立程式單獨的執行路徑,讓多部分程式碼實現同時執行。也就是說執行緒建立並執行需要給定執行緒要執行的任務。
對於之前所講的主執行緒,它的任務定義在main函式中。自定義執行緒需要執行的任務都定義在run方法中。
Thread類run方法中的任務並不是我們所需要的,只有重寫這個run方法。既然Thread類已經定義了執行緒任務的編寫位置(run方法),那麼只要在編寫位置(run方法)中定義任務程式碼即可。所以進行了重寫run方法動作。
3)多執行緒記憶體圖解
獲取執行緒名稱:
Thread.currentThread()獲取當前執行緒物件
Thread.currentThread().getName();獲取當前執行緒物件的名稱
class MyThread extends Thread { //繼承Thread MyThread(String name){ super(name); } //複寫其中的run方法 public void run(){ for (int i=1;i<=20 ;i++ ){ System.out.println(Thread.currentThread().getName()+",i="+i); } } } class ThreadDemo { public static void main(String[] args) { //建立兩個執行緒任務 MyThread d = new MyThread(); MyThread d2 = new MyThread(); d.run();//沒有開啟新執行緒, 在主執行緒呼叫run方法 d2.start();//開啟一個新執行緒,新執行緒呼叫run方法 } }
2、實現Runnable介面
1)建立執行緒的另一種方法是宣告實現 Runnable 介面的類。
該類然後實現 run 方法。然後建立Runnable的子類物件,傳入到某個執行緒的構造方法中,開啟執行緒
2)介面中的方法
Thread類構造方法
3)建立執行緒的步驟。
1、定義類實現Runnable介面。
2、覆蓋介面中的run方法。。
3、建立Thread類的物件
4、將Runnable介面的子類物件作為引數傳遞給Thread類的建構函式。
5、呼叫Thread類的start方法開啟執行緒。
public class Demo02 { public static void main(String[] args) { //建立執行緒執行目標類物件 Runnable runn = new MyRunnable(); //將Runnable介面的子類物件作為引數傳遞給Thread類的建構函式 Thread thread = new Thread(runn); Thread thread2 = new Thread(runn); //開啟執行緒 thread.start(); thread2.start(); for (int i = 0; i < 10; i++) { System.out.println("main執行緒:正在執行!"+i); } } }
自定義執行緒執行任務類
public class MyRunnable implements Runnable{ //定義執行緒要執行的run方法邏輯 @Override public void run() { for (int i = 0; i < 10; i++) { System.out.println("我的執行緒:正在執行!"+i); } } }
4)實現Runable的好處
第二種方式實現Runnable介面避免了單繼承的侷限性,所以較為常用。
實現Runnable介面的方式,更加的符合面向物件,執行緒分為兩部分,一部分執行緒物件,一部分執行緒任務。繼承Thread類,執行緒物件和執行緒任務耦合在一起。
一旦建立Thread類的子類物件,既是執行緒物件,有又有執行緒任務。實現runnable介面,將執行緒任務單獨分離出來封裝成物件,型別就是Runnable介面型別。
Runnable介面對執行緒物件和執行緒任務進行解耦。
三、執行緒的匿名內部類
使用執行緒的內匿名內部類方式,可以方便的實現每個執行緒執行不同的執行緒任務操作。
方式1:建立執行緒物件時,直接重寫Thread類中的run方法
new Thread() { public void run() { for (int x = 0; x < 40; x++) { System.out.println(Thread.currentThread().getName() + "...X...." + x); } } }.start();
方式2:使用匿名內部類的方式實現Runnable介面,重新Runnable介面中的run方法
Runnable r = new Runnable() { public void run() { for (int x = 0; x < 40; x++) { System.out.println(Thread.currentThread().getName() + "...Y...." + x); } } }; new Thread(r).start();