60 多個實例講解,完全搞懂 Java 多線程! - 知乎

https://zhuanlan.zhihu.com/p/107479862java


​JAVA 最難學的部分是哪裏?不少朋友都會說:「 java 多線程 」程序員

隨着業務量和數據的增長,企業不可避免地會使用多線程的方式處理數據。在 Java 職位的面試中,多線程也是必考的高階知識點之一。能夠說,java多線程是衡量一名 Java 程序員是否資深的關鍵標準之一。web

今天,咱們就來學習一下 Java 多線程的概念吧!面試

(點擊課程連接,開啓實驗環境,邊學邊練纔是更有效的學習方式)數據庫

Java 多線程技術實戰www.shiyanlou.com圖標

多進程與多線程的概念

初步建立多線程,理清多線程的概念。多線程

知識點

  • 多線程的概念
  • 建立多線程 —— 繼承 Thread
  • 建立多線程 —— 實現 Runnable
  • 建立多線程 —— 實現 Callable

多進程和多線程的概念

進程是程序在計算機上的一次執行活動。當你運行一個程序,你就啓動了一個進程。凡是用於完成操做系統的各類功能的進程就是系統進程,而全部由你啓動的進程都是用戶進程。

多進程

進程是程序在計算機上的一次執行活動。當你運行一個程序,你就啓動了一個進程。凡是用於完成操做系統的各類功能的進程就是系統進程,而全部由你啓動的進程都是用戶進程。異步

如圖所示每個正在運行的 .exe 程序都是一個進程。ide

多線程

進程就是有一個或多個線程構成的。而線程是進程中的實際運行單位,是獨立運行於進程之中的子任務。是操做系統進行運算調度的最小單位。可理解爲線程是進程中的一個最小運行單元。函數

進程和線程之間的關係

一個進程下包含 N 個線程。學習

舉例說明:玩英雄聯盟的時候,打開客戶端便啓動了許多個線程:排隊隊列線程、好友聊天線程、正在支付線程。在英雄聯盟這一個進程之下便啓動了 N 個線程。

咱們初學 java 邊寫代碼的時候,一般使用 main 方法進行運行,此時 main 方法執行的即是一個主線程,而所謂的多線程,便是在主線程執行的過程當中,同時執行其餘的線程。可是同時執行多個線程容易出現報錯現象,例如同時同分同秒,兩個線程同時修改一個 txt、數據庫表文件,或第一個線程沒有修改完 txt、數據庫表文件,第二個線程同時也去修改。這即是線程之間的混亂、資源競爭、髒讀,即是程序員須要去解決的疑難雜症。

建立多線程 —— 繼承 Thread

java 世界中有兩種方式建立多線程:

java 世界中有兩種方式建立多線程,分別是繼承 Thread 類,實現 Runnable 接口。

繼承 Thread 類方式建立多線程

第一步:在 webide 上右鍵單擊菜單,選擇 New File 建立新文件。

第二步:建立文件名爲 test0.java

第三步:編寫 test0.java 中繼承 Thread 類方式建立多線程的代碼以下所示:

public class test0 {

    public static void main(String[] args) {
        Thread MyThread = new MyThread();
        MyThread.start();
    }
}

class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("hello myThread" + Thread.currentThread().getName());
    }
}

第四步:編譯 test0.java 代碼:

javac test0.java

編譯以後,會產生咱們所編寫的 test0 類與 MyThread 類

第五步:運行 test 代碼:java test0

建立多線程 —— 實現 Runnable

只須要把《建立多線程 —— 繼承 Thread》中代碼修改爲以下所示便可,其它操做不變:

public class test0 {

    public static void main(String[] args) {

        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        thread.start();
    }
}

class MyRunnable implements Runnable{
    @Override
    public void run(){
        System.out.println("hello myRunnable" + Thread.currentThread().getName());
    }
}

執行結果以下所示:

一般狀況下,若是建立的線程類已經含有父類時候,此時因爲 Java 語法結構不支持多繼承的緣由,不可以再次繼承 Thread 類,此時則須要使用實現 Runnable 接口的方式來應對如此場景。另外值得說明的是,Thread 類也實現了 Runnable 接口。

實現多線程傳參 —— 有參構造

因爲多線程是由繼承 Thread 或實現 Runnable 並重寫 run() 方法,經過 thread.start() 進行運行的,而自己重寫的 run() 方法是不具有傳參能力的,那我新建的線程就接受不到我所想傳入的參數了麼?

建立 study1.java 文件

class ThreadA extends Thread{

    private String age;

    public ThreadA(String age){
        this.age = age;
    }
    @Override
    public void run() {
        System.out.println("age=" + age);
    }
}

public class study1 {
    public static void main(String[] args) {
        String age = new String("12");
        ThreadA a = new ThreadA(age);
        a.start();
    }
}

不管 extendsThread 仍是 implementsRunnable ,傳參都須要使用線程初始化的有參構造形式,達到多線程傳參的目的。也能夠作到重載有參構造,傳入各式對象。

study1 運行結果

實現多線程返回值 —— 實現 Callable<V>

一般意義上理解確實 Java 實現多線程的方式有繼承 Thread 和實現 Runnable,可是若是想實現多線程而且具備返回值的狀況下,須要實現 Callable<V> 接口,這個接口是 JDK1.5 版本之後纔出現的接口。

建立 study2.java

建立 study2.java 文件,利用實現 Callable<V> 進行返回,代碼以下所示:

import java.util.concurrent.Callable;

public class study2 {
    public static void main(String[] args) {
        MyCallable MyCallable = new MyCallable("張方興");
        String call = null;
        try {
            call = MyCallable.call();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(call);
    }
}

class MyCallable implements Callable<String>{

    private String name;

    public MyCallable(String name) {
        this.name = name;
    }

    @Override
    public String call() throws Exception {
        return "call:" + name;
    }
}

study2 運行結果

Callable<V> 接口詳解

通常繼承 Thread 的類,含有 .start() 函數,因此直接可使用 .start() 函數進行啓動。實現 Runnable 的類,須要經過 newThread(myRunnable).start(); 的方式進行啓動,即實現 Runnable 的類只是作好了一段多線程所需執行的內容,自身並無執行的能力,須要經過 Thread 類的 .start() 函數進行啓動。實現 Callable<V> 的接口,含有 .call() 函數,因此能夠直接使用 .call() 函數進行啓動,另外值得說明的是, Callable<V> 函數具備返回值,返回值爲定義類時使用的 <V> 類型,其定義是其返回。 Callable<V> 接口定義以下所示:

@FunctionalInterface
public interface Callable<V> {
    /**  * Computes a result, or throws an exception if unable to do so.  *  * @return computed result  * @throws Exception if unable to compute a result  */
    V call() throws Exception;
}

Callable<V> 用於指示接口類型聲明是由 Java 語言規範定義的功能接口。從概念上講,函數接口只有一個抽象方法。由於 java.lang.reflect.Method#isDefault()default methods 有一個實現,因此它們不是抽象的。若是接口聲明一個抽象方法重寫 java.lang.Object 的一個公共方法,則該方法也不計入接口的抽象方法計數,由於接口的任何實現都將具備來自 java.lang.Object 或其餘位置的實現。另外注意,函數接口的實例可使用 lambda 表達式、方法引用或構造函數引用建立。

Callable<V> 在須要使用返回值的狀況下,程序是同步運行的Callable<V> 。其它狀況下,程序是異步運行的

完整課程內容,請在實驗樓邊操做邊學習。

Java 多線程技術實戰www.shiyanlou.com圖標
相關文章
相關標籤/搜索