日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java多线程的实现方式-Thread 类,Runnable 接口

發(fā)布時間:2025/3/20 java 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java多线程的实现方式-Thread 类,Runnable 接口 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

在 Java 的 JDK 開發(fā)包中,已經自帶了對多線程技術的支持,可以方便地進行多線程編程。實現(xiàn)多線程編程的方式主要有兩種:一種是繼承 Thread 類,另一種是實現(xiàn) Runnable 接口。下面詳細介紹這兩種具體實現(xiàn)方式。

繼承 Thread 類

在學習如何實現(xiàn)多線程前,先來看看 Thread 類的結構,如下:

public class Thread implements Runnable

從上面的源代碼可以發(fā)現(xiàn),Thread 類實現(xiàn)了 Runnable 接口,它們之間具有多態(tài)關系。

其實,使用繼承 Thread 類的方式實現(xiàn)多線程,最大的局限就是不支持多繼承,因為 Java 語言的特點就是單根繼承,所以為了支持多繼承,完全可以實現(xiàn) Runnable 接口的方式,一邊實現(xiàn)一邊繼承。但用這兩種方式創(chuàng)建的線程在工作時的性質是一樣的,沒有本質的區(qū)別。

Thread 類有如下兩個常用構造方法:

public Thread(String threadName) public Thread()

繼承 Thread 類實現(xiàn)線程的語法格式如下:

public class NewThreadName extends Thread { //NewThreadName 類繼承自 Thread 類public void run(){//線程的執(zhí)行代碼在這里} }

線程實現(xiàn)的業(yè)務代碼需要放到 run() 方法中。當一個類繼承 Thread 類后,就可以在該類中覆蓋 run() 方法,將實現(xiàn)線程功能的代碼寫入 run() 方法中,然后同時調用 Thread 類的 start() 方法執(zhí)行線程,也就是調用 run() 方法。

Thread 對象需要一個任務來執(zhí)行,任務是指線程在啟動時執(zhí)行的工作,該工作的功能代碼被寫在 run() 方法中。當執(zhí)行一個線程程序時,就會自動產生一個線程,主方法正是在這個線程上運行的。當不再啟動其他線程時,該程序就為單線程程序。主方法線程啟動由 Java 虛擬機負責,開發(fā)人員負責啟動自己的線程。

如下代碼演示了如何啟動一個線程:

new NewThreadName().start(); //NewThreadName 為繼承自 Thread 的子類

注意:如果 start() 方法調用一個已經啟動的線程,系統(tǒng)將會拋出 IllegalThreadStateException 異常。

例 1
編寫一個 Java 程序演示線程的基本使用方法。這里創(chuàng)建的自定義線程類為 MyThread,此類繼承自 Thread,并在重寫的 run() 中輸出一行字符串。

MyThread 類代碼如下:

public class MyThread extends Thread {@Overridepublic void run(){super.run();System.out.println("這是線程類 MyThread");} }

接下來編寫啟動 MyThread 線程的主方法,代碼如下:

public static void main(String[] args) {MyThread mythread=new MyThread(); //創(chuàng)建一個線程類mythread.start(); //開啟線程System.out.println("運行結束!"); //在主線程中輸出一個字符串 }

運行上面的程序將看到如下所示的運行效果。

運行結束!
這是線程類 MyThread

從上面的運行結果來看,MyThread 類中 run() 方法執(zhí)行的時間要比主線程晚。這也說明在使用多線程技術時,代碼的運行結果與代碼執(zhí)行順序或調用順序是無關的。同時也驗證了線程是一個子任務,CPU 以不確定的方式,或者說以隨機的時間來調用線程中的 run() 方法,所以就會出現(xiàn)先打印“運行結束!”,后輸出“這是線程類MyThread”這樣的結果了。

例 2

上面介紹了線程的調用具有隨機性,為了更好地理解這種隨機性這里編寫了一個案例進行演示。

(1) 首先創(chuàng)建自定義的線程類 MyThread01,代碼如下:

public class MyThread extends Thread {public void run(){try {for(int i=0;i<10;i++){int time=(int) (Math.random()*1000);Thread.sleep(time);System.out.println("當前線程名稱:"+Thread.currentThread().getName());}} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}} }

(2) 接下來編寫主線程代碼,在這里除了啟動上面的 MyThread01 線程外,還實現(xiàn)了 MyThread01 線程相同的功能。主線程的代碼如下:

public class Test {public static void main(String[] args){ try{ MyThread thread=new MyThread(); thread.setName("myThread"); thread.start(); for (int i=0;i<10;i++){ int time=(int)(Math.random()*1000); Thread.sleep(time); System.out.println("主線程名稱="+Thread.currentThread().getName()); } }catch(InterruptedException e){ e.printStackTrace(); }}}

在上述代碼中,為了展現(xiàn)出線程具有隨機特性,所以使用隨機數(shù)的形式來使線程得到掛起的效果,從而表現(xiàn)出 CPU 執(zhí)行哪個線程具有不確定性。

MyThread類中的 start() 方法通知“線程規(guī)劃器”此線程已經準備就緒,等待調用線程對象的 run() 方法。這個過程其實就是讓系統(tǒng)安排一個時間來調用 Thread 中的 run() 方法,也就是使線程得到運行,啟動線程,具有異步執(zhí)行的效果。

如果調用代碼 thread.run() 就不是異步執(zhí)行了,而是同步,那么此線程對象并不交給“線程規(guī)劃器”來進行處理,而是由 main 主線程來調用 run() 方法,也就是必須等 run() 方法中的代碼執(zhí)行完后才可以執(zhí)行后面的代碼。

這種采用隨機數(shù)延時調用線程的方法又稱為異步調用,程序運行的效果如下所示。

當前線程名稱:myThread 主線程名稱=main 主線程名稱=main 主線程名稱=main 當前線程名稱:myThread 主線程名稱=main 主線程名稱=main 當前線程名稱:myThread 當前線程名稱:myThread 主線程名稱=main 當前線程名稱:myThread 主線程名稱=main 當前線程名稱:myThread 主線程名稱=main 當前線程名稱:myThread 主線程名稱=main 當前線程名稱:myThread 主線程名稱=main 當前線程名稱:myThread 當前線程名稱:myThread

例 3
除了異步調用之外,同步執(zhí)行線程 start() 方法的順序不代表線程啟動的順序。下面創(chuàng)建一個案例演示同步線程的調用。

(1) 首先創(chuàng)建自定義的線程類 MyThread,代碼如下:

public class MyThread extends Thread {private int i;public MyThread(int i){super();this.i=i;}public void run(){System.out.println("當前數(shù)字:"+i);} }

(2) 接下來編寫主線程代碼,在這里創(chuàng)建 10 個線程類 MyThread,并按順序依次調用它們的 start() 方法。主線程的代碼如下:

public class Test {public static void main(String[] args){ MyThread t11=new MyThread(1); MyThread t12=new MyThread(2); MyThread t13=new MyThread(3); MyThread t14=new MyThread(4); MyThread t15=new MyThread(5); MyThread t16=new MyThread(6); MyThread t17=new MyThread(7); MyThread t18=new MyThread(8); MyThread t19=new MyThread(9); MyThread t110=new MyThread(10); t11.start(); t12.start(); t13.start(); t14.start(); t15.start(); t16.start(); t17.start(); t18.start(); t19.start(); t110.start(); }}

程序運行后的結果如下所示,從運行結果中可以看到,雖然調用時數(shù)字是有序的,但是由于線程執(zhí)行的隨機性,導致輸出的數(shù)字是無序的,而且每次順序都不一樣。

當前數(shù)字:1 當前數(shù)字:5 當前數(shù)字:4 當前數(shù)字:2 當前數(shù)字:3 當前數(shù)字:7 當前數(shù)字:6 當前數(shù)字:8 當前數(shù)字:9 當前數(shù)字:10

實現(xiàn) Runnable 接口

如果要創(chuàng)建的線程類已經有一個父類,這時就不能再繼承 Thread 類,因為 Java 不支持多繼承,所以需要實現(xiàn) Runnable 接口來應對這樣的情況。

實現(xiàn) Runnable 接口的語法格式如下:

public class thread extends Object implements Runnable

提示:從 JDK 的 API 中可以發(fā)現(xiàn),實質上 Thread 類實現(xiàn)了 Runnable 接口,其中的 run() 方法正是對 Runnable 接口中 run() 方法的具體實現(xiàn)。

實現(xiàn) Runnable 接口的程序會創(chuàng)建一個 Thread 對象,并將 Runnable 對象與 Thread 對象相關聯(lián)。Thread 類有如下兩個與 Runnable 有關的構造方法:

public Thread(Runnable r); public Thread(Runnable r,String name);

使用上述兩種構造方法之一均可以將 Runnable 對象與 Thread 實例相關聯(lián)。使用 Runnable 接口啟動線程的基本步驟如下。

  • 創(chuàng)建一個 Runnable 對象。
  • 使用參數(shù)帶 Runnable 對象的構造方法創(chuàng)建 Thread 實例。
  • 調用 start() 方法啟動線程。
  • 通過實現(xiàn) Runnable 接口創(chuàng)建線程時開發(fā)人員首先需要編寫一個實現(xiàn) Runnable 接口的類,然后實例化該類的對象,這樣就創(chuàng)建了 Runnable 對象。接下來使用相應的構造方法創(chuàng)建 Thread 實例。最后使用該實例調用 Thread 類的 start() 方法啟動線程,如圖 1 所示。


    例 1
    編寫一個簡單的案例演示如何實現(xiàn) Runnable 接口,以及如何啟動線程。

    (1) 首先創(chuàng)建一個自定義的 MyRmmable 類,讓該類實現(xiàn) Runnable 接口,并在 run() 方法中輸出一個字符串。代碼如下:

    public class MyRunnable implements Runnable{@Overridepublic void run() {System.out.println("MyRunnable運行中!");}}

    (2) 接下來在主線程中編寫代碼,創(chuàng)建一個 MyRunnable 類實例,并將該實例作為參數(shù)傳遞給 Thread 類的構造方法,最后調用 Thread 類的 start() 方法啟動線程。具體實現(xiàn)代碼如下:

    public class Test {public static void main(String[] args){ Runnable runnable=new MyRunnable();Thread thread=new Thread(runnable);thread.start();System.out.println("主線程運行結束");}}

    如上述代碼所示,啟動線程的方法非常簡單。運行結果如下所示,同樣驗證了線程執(zhí)行的隨機性。

    主線程運行結束! MyRunnable運行中!

    注意:要啟動一個新的線程,不是直接調用 Thread 子類對象的 run() 方法,而是調用 Thread 子類的 start() 方法。Thread 類的 start() 方法會產生一個新的線程,該線程用于執(zhí)行 Thread 子類的 run() 方法。

    兩種方法的比較

    雖然 Thread 類和 Runnable 接口都可以創(chuàng)建線程,但是它們也都有各自的優(yōu)缺點。

  • 繼承 Thread 類的優(yōu)缺點
  • 當一個 run() 方法體現(xiàn)在繼承 Thread 類中時,可以用 this 指向實際控制運行的 Thread 實例。因此,代碼不需要使用以下控制語句:

    Thread.currenThread().sleep();

    不再使用上面的控制語句,而是可以簡單地使用 Threadsleep() 方法,繼承 Thread 類的方式使代碼變得簡單易讀。

  • 實現(xiàn) Runnable 接口的優(yōu)缺點
  • 從面向對象的角度來看,Thread 類是一個虛擬處理機嚴格的封裝,因此只有當處理機模型修改或擴展時,才應該繼承該類。由于 Java 技術只允許單一繼承,因此如果已經繼承了 Thread 類,就不能再繼承其他任何類,這會使用戶只能采用實現(xiàn) Runnable 接口的方式創(chuàng)建線程。

    Thread和Runnable的區(qū)別

    如果一個類繼承Thread,則不適合資源共享。但是如果實現(xiàn)了Runable接口的話,則很容易的實現(xiàn)資源共享。

    總結:

    實現(xiàn)Runnable接口比繼承Thread類所具有的優(yōu)勢:

    1):適合多個相同的程序代碼的線程去處理同一個資源

    2):可以避免java中的單繼承的限制

    3):增加程序的健壯性,代碼可以被多個線程共享,代碼和數(shù)據(jù)獨立

    4):線程池只能放入實現(xiàn)Runable或callable類線程,不能直接放入繼承Thread的類

    提醒一下大家:main方法其實也是一個線程。在java中所以的線程都是同時啟動的,至于什么時候,哪個先執(zhí)行,完全看誰先得到CPU的資源。

    在java中,每次程序運行至少啟動2個線程。一個是main線程,一個是垃圾收集線程。因為每當使用java命令執(zhí)行一個類的時候,實際上都會啟動一個JVM,每一個jVM實習在就是在操作系統(tǒng)中啟動了一

    總結

    以上是生活随笔為你收集整理的Java多线程的实现方式-Thread 类,Runnable 接口的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。