EduCoder-JavaJava高級特性 - 多線程基礎(1)實現代碼以及相關知識點

我是小康小白,一個平平無奇的Java小白。熱愛有趣的文字,生活和遠方。

在這裏插入圖片描述

第1關:創建線程

任務描述

本關任務:創建一個Java線程執行特定任務。

相關知識
不知道你有沒有發現,截止目前,我們編寫的代碼都是在main()函數中依照編寫代碼的順序從上到下依次運行的。

但是我們平常使用的軟件基本都是可以多個任務同時執行的,這其中的運行機制是什麼呢?這一小節我們就來探討。

本小節我們來學習Java中程序是如何同時執行多個任務的。

  1. 什麼是線程、什麼是進程
    在Java中要同時執行(如果是單核,準確的說是交替執行)多個任務,使用的是多線程,而要理解線程,我們先要了解什麼是進程什麼是線程。

一般的定義:進程是指在操作系統中正在運行的一個應用程序,線程是指進程內獨立執行某個任務的一個單元。

怎麼理解呢?

比如說QQ是是一個進程,如果你在和A朋友語音聊天的同時和B朋友打字聊天,同時還在QQ羣下載圖片,這三個
操作就相當於開啓了三個線程,可以說有了線程之後我們設計的程序就可以一邊執行A操作,一邊執行B操作了。

線程和進程有什麼區別呢?首先最直觀的就是:一個進程可擁有多個線程。
具體比較:

  • 調度
    進程擁有資源;
    線程是調度和分派的基本單位;
    同一進程中線程的切換不會引起進程的切換;
    進程間的線程切換則會引起進程切換從而導致資源切換等。

  • 併發性
    進程:進程和進程之間可併發執行 ;
    線程:除了進程間的併發執行還可以線程之間併發執行;
    線程的併發性更高。

*擁有資源 *
線程並不能擁有資源,只有進程才擁有資源。

  • 系統開銷
    進程創建、切換和撤銷都會導致系統爲之創建或者回收進程控制卡以及資源,但是線程的創建以及線程間的切換並不會引起系統做這些事兒,所以線程的系統開銷明顯更小。

如何創建線程
在這裏我們主要掌握兩種創建線程的方式。

1.繼承Thread類;

我們可以使用繼承Thread類的方式來創建一個線程。
創建一個類來繼承Thread類,重寫父類的run方法,就實現了創建我們自己的線程了。之後調用線程的start方法,就算是開啓了一個線程了。

示例:

class MyThread extends Thread{
    private String name;
    public MyThread(String name) {
        super();
        this.name = name;
    }
    public void run() {
        System.out.println("線程" + name +"開始運行");
        for (int i = 0; i < 5; i++) {
            System.out.println("線程" +  name + "運行" + i);
        }
        System.out.println("線程" + name + "結束");
    }
}
public class Test {
    public static void main(String[] args) {
        Thread t = new MyThread("T!");
        t.start();
        Thread t2 = new MyThread("T2");
        t2.start();
    }
}

運行結果:

線程T!開始運行
線程T2開始運行
線程T!運行0
線程T2運行0
線程T!運行1
線程T2運行1
線程T!運行2
線程T!運行3
線程T!運行4
線程T2運行2
線程T2運行3
線程T2運行4
線程T2結束
線程T!結束

運行這段代碼我們會發現,線程是交替運行的,並且每次運行輸出的結果都不一樣,輸出是隨機的。

2.實現Runnable接口。

最簡單創建線程的方法就是實現一個Runnable接口了,實際上所有的線程都是直接或者間接實現了Runnable接口的,上一個例子中Thread類其實就實現了Runnable接口。

示例:

class MyThread implements Runnable {
    private String name;
    private Thread mythread;
    public MyThread(String name) {
        super();
        this.name = name;
    }
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("線程" + name + "運行" + i);
        }
        System.out.println("線程" + name + "結束");
    }
    public void start() {
        System.out.println("線程開始: " + name);
        if (mythread == null) {
            mythread = new Thread(this, name);
            mythread.start();
        }
    }
}
public class Test {
    public static void main(String[] args) {
        MyThread t1 = new MyThread("T1");
        t1.start();
        MyThread t2 = new MyThread("T2");
        t2.start();
    }
}

運行結果:

線程開始: T1
線程開始: T2
線程T1運行0
線程T2運行0
線程T1運行1
線程T1運行2
線程T1運行3
線程T1運行4
線程T1結束
線程T2運行1
線程T2運行2
線程T2運行3
線程T2運行4
線程T2結束

在Java1.5版本之後,還提供了一種創建線程的方式: 通過Callable 和 Future 創建線程,這個我們將在之後的實訓中學習到。

創建線程的兩種方式對比

實現Runnable創建線程時,線程類只是實現了Runnable接口,還可以繼承其他的類。

繼承THread類創建線程時,線程類繼承了Thread類,不能再繼承其他類。不過這種方式編寫簡單,如果需要訪問當前線程,則無需使用 Thread.currentThread()方法,直接使用this即可獲得當前線程。

java程序默認啓動的線程

在Java中,每次程序運行至少啓動2個線程。一個是main線程,一個是垃圾收集線程。因爲每當使用Java命令執行一個類的時候,實際上都會啓動一個jvm,每一個jvm實際在就是在操作系統中啓動了一個進程。

編程要求
請仔細閱讀右側代碼,根據方法內的提示,在Begin - End區域內進行代碼補充,具體任務如下:

使用繼承Thread類的方式創建一個名爲 ThreadClassOne 的類,重寫的run方法需要實現輸出0-10之間的奇數,輸出結果如下:
1 3 5 7 9;

使用實現Runnable接口的方式創建一個名爲ThreadClassTwo的類,重寫run方法,編寫start方法,run方法需要實現打印0-10之間的偶數,輸出結果如下:
0 2 4 6 8 10

測試說明
平臺會對你編寫的代碼進行測試,若是與預期輸出相同,則算通關。

因爲需要完成兩個文件的編寫,所以你需要在右側進行文件切換。

平臺會判斷你定義的類是否是一個線程類,並且調用run方法,判斷是否達到預期的輸出結果。

實現代碼

package step1;

//請在此添加實現代碼
/********** Begin **********/
public class ThreadClassOne  extends Thread   {
    public void run(){
        for(int i=1;i<10;i+=2){
            System.out.print(i+" ");
        }
    }
}
class ThreadClassTwo implements Runnable{
    public void run(){
        for(int i=0;i<=10;i+=2){
            System.out.print(i+" ");
        }
    }
    public void start(){

    }
}


/********** End **********/

以上代碼直接cv即可通過,但筆者建議理解後自己實踐
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章