多線程--多線程創建方式

線程與進程的區別

  • 每個正在系統上運行的程序都是一個進程。每個進程包含一到多個線程。線程是一組指令的集合,或者是程序的特殊段,它可以在程序裏獨立執行。也可以把它理解爲代碼運行的上下文。所以線程基本上是輕量級的進程,它負責在單個程序裏執行多任務。通常由操作系統負責多個線程的調度和執行。

  • 使用線程可以把佔據時間長的程序中的任務放到後臺去處理,程序的運行速度可能加快,在一些等待的任務實現上如用戶輸入、文件讀寫和網絡收發數據等,線程就比較有用了。在這種情況下可以釋放一些珍貴的資源如內存佔用等等。

  • 如果有大量的線程,會影響性能,因爲操作系統需要在它們之間切換,更多的線程需要更多的內存空間,線程的中止需要考慮其對程序運行的影響。通常塊模型數據是在多個線程間共享的,需要防止線程死鎖情況的發生。

  • 總結:進程是所有線程的集合,每一個線程是進程中的一條執行路徑。

多線程應用場景

  • 主要體現是用多線程來提高程序效率,

簡單舉例 :

  1. 迅雷 ,愛奇藝 等app 下載視頻,vip同時下載3-5個視頻

  2. 數據庫連接池

    注: 多線程不能提高下載速度,但是能同時下載多個資源

多線程創建方式

1. 繼承Thread類,重寫run()方法

package com.yxl.demo.ThreadTest;

public class test1 {
    //main方法
    public static void main(String[] args) {
        System.out.println("---多線程開始---");
        // new 一個線程
        CreateThread createThread = new CreateThread();
        // 執行線程 注:不是調用run方法
        System.out.println("---多線程啓動---");
        createThread.start();
        System.out.println("---多線程結束---");
    }
}

class CreateThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 10 ; i++) {
            System.out.println("i : "+i);
        }
    }
}

代碼運行結果:
在這裏插入圖片描述

  1. 實現Runnable接口,重寫run方法
package com.yxl.demo.ThreadTest;

public class Test2 {
    //main方法
    public static void main(String[] args) {
        System.out.println("---多線程開始---");
        // new 一個線程
        CreateRunnable createRunnable = new CreateRunnable();

        Thread thread =new Thread(createRunnable);
        // 執行線程 注:不是調用run方法
        System.out.println("---多線程啓動---");
        thread.start();
        System.out.println("---多線程結束---");
    }
}

class CreateRunnable implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("i : " + i);
        }
    }
}

運行結果:
在這裏插入圖片描述

使用繼承Thread類還是使用實現Runnable接口好?

  • 使用實現實現Runnable接口好,原因實現了接口還可以繼續繼承,繼承了類不能再繼承。

啓動線程是使用調用start方法還是run方法?

  • 開始執行線程 注意 開啓線程不是調用run方法,而是start方法 調用run知識使用實例調用方法。
  1. 實現Callable接口 (有返回值)
package com.yxl.demo.ThreadTest;

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

public class Test4 {
    public static void main(String[] args) {
        //nwe 一個Callable
        Callable<Object> oneCallable = new Task<Object>();
        //通過FutureTask包裝器來實現的線程
        FutureTask<Object> oneTask = new FutureTask<Object>(oneCallable);
        Thread t = new Thread(oneTask);

        t.start();

    }

}

class Task<Object> implements Callable<Object> {

    //重寫call方法
    @Override
    public Object call() throws Exception {
        // TODO Auto-generated method stub
        System.out.println(Thread.currentThread().getName()+"-->我是通過實現Callable接口通過FutureTask包裝器來實現的線程");
        return null;
    }
}

獲取線程對象以及名稱
常用線程api方法

start()	啓動線程
currentThread()	獲取當前線程對象
getID()	獲取當前線程ID      Thread-編號  該編號從0開始
getName()	獲取當前線程名稱
sleep(long mill)	休眠線程
Stop()	停止線程,
常用線程構造函數
Thread()	分配一個新的 Thread 對象
Thread(String name)	分配一個新的 Thread對象,具有指定的 name正如其名。
Thread(Runable r)	分配一個新的 Thread對象
Thread(Runable r, String name)	分配一個新的 Thread對象

守護線程

  • Java中有兩種線程,一種是用戶線程,另一種是守護線程。 用戶線程是指用戶自定義創建的線程,主線程停止,用戶線程不會停止
    守護線程當進程不存在或主線程停止,守護線程也會被停止。 使用setDaemon(true)方法設置爲守護線程
  • 守護進程也叫後臺進程,是一種爲其他線程提供服務的一種線程。當虛擬機檢測到沒有用戶進程執行了的話,即使還有後臺進程,JVM也有可能會退出的。
package com.yxl.demo.ThreadTest;

public class Test3 {

    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(100); 
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
                    System.out.println("我是子線程...");
                }
            }
        });
        thread.setDaemon(true);  //設置爲守護線程
        thread.start();
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(100);
            } catch (Exception e) {

            }
            System.out.println("我是主線程");
        }
        System.out.println("主線程執行完畢!");
    }
}

多線程運行狀態

  • 線程從創建、運行到結束總是處於下面五個狀態之一:新建狀態、就緒狀態、運行狀態、阻塞狀態及死亡狀態。

新建狀態

當用new操作符創建一個線程時, 例如new Thread®,線程還沒有開始運行,此時線程處在新建狀態。 當一個線程處於新生狀態時,程序還沒有開始運行線程中的代碼

就緒狀態

一個新創建的線程並不自動開始運行,要執行線程,必須調用線程的start()方法。當線程對象調用start()方法即啓動了線程,start()方法創建線程運行的系統資源,並調度線程運行run()方法。當start()方法返回後,線程就處於就緒狀態。
處於就緒狀態的線程並不一定立即運行run()方法,線程還必須同其他線程競爭CPU時間,只有獲得CPU時間纔可以運行線程。因爲在單CPU的計算機系統中,不可能同時運行多個線程,一個時刻僅有一個線程處於運行狀態。因此此時可能有多個線程處於就緒狀態。對多個處於就緒狀態的線程是由Java運行時系統的線程調度程序(thread scheduler)來調度的。

運行狀態

當線程獲得CPU時間後,它才進入運行狀態,真正開始執行run()方法.

阻塞狀態

線程運行過程中,可能由於各種原因進入阻塞狀態:
    1>線程通過調用sleep方法進入睡眠狀態;
    2>線程調用一個在I/O上被阻塞的操作,即該操作在輸入輸出操作完成之前不會返回到它的調用者;
    3>線程試圖得到一個鎖,而該鎖正被其他線程持有;
    4>線程在等待某個觸發條件;

死亡狀態

有兩個原因會導致線程死亡:

  1. run方法正常退出而自然死亡,
  2. 一個未捕獲的異常終止了run方法而使線程猝死。
    爲了確定線程在當前是否存活着(就是要麼是可運行的,要麼是被阻塞了),需要使用isAlive方法。如果是可運行或被阻塞,這個方法返回true; 如果線程仍舊是new狀態且不是可運行的, 或者線程死亡了,則返回false.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章