天天看點

多線程-01-建立線程的三種方式

多線程<small>建立線程的三種方式</small>

程序和線程

幾乎所有的作業系統都支援同時運作多個任務,一個任務通常就是一個程式,每個運作中的程式就是一個程序Process。當一個程式運作時,内部可能包含多個順序執行流,每個順序執行流就是一個線程Thread。

線程是程序的組成部分,一個程序可以擁有多個線程,一個線程必須擁有一個父程序。

線程可以擁有自己的堆棧,自己的程式計數器和自己的局部變量,但是線程不擁有自己的資源。它與父程序的其他線程共享該程序的所有資源。

線程的執行是搶占式的,是以任何一個線程都有可能被挂起,以便另外一個線程的執行。

線程可以建立和撤銷另外一個線程。

線程共享的環境包括:程序的代碼段,程序的共有資料等。利用這些共享的資料,線程很容易實作項目之間的通信。

1. 繼承Thread類建立線程類

  1. 定義Thread類的子類,并重寫run()方法,該run(0方法的方法體代表了線程需要完成的任務,是以run()方法稱為線程執行體。
  2. 建立了Thread類的子類,級建立了線程對象。
  3. 調用線程對象的start()方法來啟動該線程。

currenThread(),擷取目前線程對象

getName(),目前線程的名字,預設是main ,Thread-0,Thread-1,Thread-n

package com.manyThread;

/**
 * @author futao
 * Created on 18-1-8-下午8:49.
  * 多線程的實作方式1,繼承Thread類,重寫run()方法
 */
public class FirstThread extends Thread {
    private int i;

    @Override
    public void run() {
        for (; i < 1000; i++) {
            System.out.println("==" + this.getName() + " " + i);
        }
    }

    public static void main(String[] args) {
        for (int i = 0; i < 1000; i++) {
            System.out.println("main===" + Thread.currentThread().getName() + "    " + i);
            if (i == 20) {
                FirstThread firstThread = new FirstThread();
                firstThread.setName("Niu");
                firstThread.start();

                new FirstThread().start();
            }
        }
    }
}

           

可以發現,i的值是不連續的,是以用繼承Thread的方式實作的多線程是不能夠共享線程的執行個體變量的。

使用繼承Thread類的方法來建立線程時,多個線程之間無法共享線程的執行個體變量,因為每個線程都需要執行個體化一個對象。

2. 實作Runnable接口建立線程類

  1. 定義Runnable接口的實作類,并重寫該接口的run()方法,該run()方法的方法體同樣是該線程的線程執行體。
  2. 建立Runnable實作類的執行個體,并以此執行個體作為Thread的target來建立Thread對象,該Thread對象才是真的線程對象。
package com.manyThread;

/**
 * @author futao
 * Created on 18-1-8-下午9:10.
 * 多線程的實作方式2,實作Runnable接口,重寫run()方法
 */
public class FirstRunnable implements Runnable {
    private int i;

    @Override
    public void run() {
        for (; i < 1000; i++) {
            System.out.println(Thread.currentThread().getName() + "===" + i);
        }
    }

    public static void main(String[] args) {


        for (int j = 0; j < 100; j++) {
            System.out.println("main" + j);
            if (j == 20) {
                FirstRunnable firstRunnable = new FirstRunnable();
                /*Runnable的實作類的對象僅僅用來作為new Thread()的target*/
                Thread thread = new Thread(firstRunnable, "myNewThread");
                thread.start();

                Thread thread1 = new Thread(firstRunnable, "2thread");
                thread1.start();

            }
        }
    }
}
           

變量 i 的值是連續的,是以通過實作Runnable接口的方式實作的多線程是可以共享線程類的執行個體變量的

這是因為在這種方式下,程式所建立的Runnable對象隻是線程的target,而多個線程可以共享同一個target,是以多個線程可以共享同一個線程類(實際上是線程的target類)的執行個體變量。

是以通過實作Runnable接口建立的多線程時,

Thread

類的作用就是把run()方法包裝成線程執行體。

3.使用Callable和Future建立線程

Runnable接口的增強版
  1. 建立Callable接口的實作類,并實作call()方法,作為線程的執行體,且該call()方法有傳回值,可以直接使用Lambda表達式建立Callable對象
  2. 使用FutureTask類來包裝Callable對象,該FutureTask對象封裝了該Callable對象的call()方法的傳回值。
  3. 使用FutureTask對象作為Thread對象的target建立并且啟動線程
  4. 調用FutureTask對象的get()方法來獲得子線程執行之後的傳回值。(将導緻主線程被阻塞,直到call()方法傳回傳回值)
package com.manyThread;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * @author futao
 * Created on 18-1-11-上午10:21.
 */
public class FirstCallable implements Callable {
    @Override
    public Object call() throws Exception {
        return 6666;
    }

    public static void main(String[] args) {
//        FirstCallable firstCallable = new FirstCallable();
//        FutureTask futureTask = new FutureTask(firstCallable);
//        Thread thread = new Thread(futureTask);
//        thread.start();
//        try {
//            System.out.println(futureTask.get());
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        } catch (ExecutionException e) {
//            e.printStackTrace();
//        }


        FutureTask futureTask1 = new FutureTask(() -> {
            int i = 0;
            for (; i <= 100; i++) {
                System.out.println(Thread.currentThread().getName() + i);
            }
            return i;
        });
        for (int i = 0; i < 50; i++) {
            System.out.println(Thread.currentThread().getName() + i);
            if (i == 20) {
                Thread thread = new Thread(futureTask1);
                thread.start();
                try {
                    /*get()方法将導緻主線程被阻塞,直到call()方法結束并傳回傳回值為止*/
                    System.out.println(futureTask1.get());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
            }

        }

    }
}

           

4. 建立線程的三種方式比較

多線程-01-建立線程的三種方式

繼續閱讀