java多線程(一)創建線程的四種方式


1.   什么是並發與並行

要想學習多線程,必須先理解什么是並發與並行

並行:指兩個或多個事件在同一時刻發生(同時發生)。

並發:指兩個或多個事件在同一個時間段內發生。

 

2.   什么是進程、線程

進程:

進程是正在運行的程序的實例。

進程是線程的容器,即一個進程中可以開啟多個線程。

比如打開一個瀏覽器、打開一個word等操作,都會創建進程。

 

線程:

線程是進程內部的一個獨立執行單元;

一個進程可以同時並發運行多個線程;

比如進程可以理解為醫院,線程是掛號、就診、繳費、拿葯等業務活動

 

多線程:多個線程並發執行。

 

 

3.   線程創建

Java中線程有四種創建方式:

l  繼承Thread類

l  實現Runnable接口

l  實現Callable接口

l  線程池

3.1. 繼承Thread類

3.1.1.   第一步:創建自定義線程類

package com.creatThera;

import java.util.Date;

/**
 * @Auther: lanhaifeng
 * @Date: 2019/11/20 0020 09:20
 * @Description: 繼承Thread類實現多線程
 * @statement:
 */
public class MyThread extends Thread{

    public void run() {
        for (int i = 0; i<10; i++){
            System.out.println("mythread線程正在執行:"+i);
        }
    }

    public static void main(String[] args) {
        MyThread myThread=new MyThread();
        myThread.start();
        for (int i = 0; i<10; i++){
            System.out.println("主線程正在執行:"+i);
        }
    }
}

執行效果如下:

 

3.2. 實現Runnable接口

3.2.1.   第一步:創建自定義類實現Runnable接口

package com.creatThera;

/**
 * @Auther: lanhaifeng
 * @Date: 2019/11/20 0020 09:32
 * @Description:實現runnable接口創建線程
 * @statement:
 */
public class MyRunable implements Runnable {

    public void run() {
        for (int i = 0; i<10; i++){
            System.out.println("myRunnable線程正在執行:"+i);
        }
    }

    //測試線程
    public static void main(String[] args) {
        Thread thread=new Thread(new MyRunable());
        thread.start();
        for (int i = 0; i<10; i++){
            System.out.println("主線程正在執行:"+i);
        }
    }
}

執行效果如下:

 

3.3. 實現Callable接口

3.3.1.   FutureTask介紹

Callable需要使用FutureTask類幫助執行,FutureTask類結構如下:

 

Future接口:

判斷任務是否完成:isDone()

能夠中斷任務:cancel()

能夠獲取任務執行結果:get()

3.3.2.   第一步:創建自定義類實現Callable接口

package com.creatThera;

import java.util.concurrent.*;

/**
 * @Auther: lanhaifeng
 * @Date: 2019/11/20 0020 09:41
 * @Description: 實現callable接口創建線程
 * @statement: callable接口是有返回值的
 */
public class MyCallnable implements Callable<String> {

    public String call() throws Exception {
        for (int i = 0; i < 10; i++) {
            System.out.println("myCallable線程正在執行:"+i);
        }
        return "MyCallabe線程執行完畢";
    }

    //測試
    public static void main(String[] args) {
        //創建futuretask對象
        FutureTask<String> futureTask = new FutureTask<String>(new MyCallnable());
        //創建Thread對象,傳入futureTask
        Thread thread=new Thread(futureTask);
        thread.start();
        for (int i = 0; i<10; i++){
            System.out.println("主線程正在執行:"+i);
        }
    }
}

運行效果圖如下:

 

3.4. 線程池-Executor

3.4.1.   線程池線類關系圖

Executor接口

  聲明了execute(Runnable runnable)方法,執行任務代碼

ExecutorService接口:

  繼承Executor接口,聲明方法:submit、invokeAll、invokeAny以及shutDown等

AbstractExecutorService抽象類:

  實現ExecutorService接口,基本實現ExecutorService中聲明的所有方法

ScheduledExecutorService接口:

  繼承ExecutorService接口,聲明定時執行任務方法

ThreadPoolExecutor類:

  繼承類AbstractExecutorService,實現execute、submit、shutdown、shutdownNow方法

ScheduledThreadPoolExecutor類:

  繼承ThreadPoolExecutor類,實現ScheduledExecutorService接口並實現其中的方法

Executors類:

  提供快速創建線程池的方法

3.4.2.   第一步:創建自定義類實現Runnable接口

package com.creatThera;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @Auther: lanhaifeng
 * @Date: 2019/11/20 0020 09:52
 * @Description:使用線程池創建線程
 * @statement: 
 */
public class MyExecutors {

    //實現runnable接口,線程池只支持runnable和callable
    class MyRunnable implements Runnable{
        public void run() {
            for (int i = 0; i<10; i++){
                System.out.println("myRunnable線程正在執行:"+i);
            }
        }
    }

    //測試用線程池創建線程
    public static void main(String[] args) {
        //1.使用Executors創建線程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        //2.通過線程池執行線程,線程池只支持runnable和callable
        executorService.execute(new MyRunable());
        //3.主線程循環打印
        for (int i=0; i<10; i++){
            System.out.println("main主線程正在執行:"+i);
        }
    }

}
實現效果如下:

3.5. 小結

3.5.1.   實現接口和繼承Thread類比較

l  接口更適合多個相同的程序代碼的線程去共享同一個資源。

l  接口可以避免java中的單繼承的局限性。

l  接口代碼可以被多個線程共享,代碼和線程獨立。

l  線程池只能放入實現Runable或Callable接口的線程,不能直接放入繼承Thread的類。

擴充:

在java中,每次程序運行至少啟動2個線程。一個是main線程,一個是垃圾收集線程。

3.5.2.   Runnable和Callable接口比較

相同點:

l  兩者都是接口;

l  兩者都可用來編寫多線程程序;

l  兩者都需要調用Thread.start()啟動線程;

不同點:

l  實現Callable接口的線程能返回執行結果;而實現Runnable接口的線程不能返回結果;

l  Callable接口的call()方法允許拋出異常;而Runnable接口的run()方法的不允許拋異常;

l  實現Callable接口的線程可以調用Future.cancel取消執行 ,而實現Runnable接口的線程不能

注意點:

Callable接口支持返回執行結果,此時需要調用FutureTask.get()方法實現,此方法會阻塞主線程直到獲取‘將來’結果;當不調用此方法時,主線程不會阻塞!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM