1. 程式人生 > 實用技巧 >JAVA之多執行緒

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();