1. 程式人生 > >java併發程式設計一一多執行緒基礎快速入門

java併發程式設計一一多執行緒基礎快速入門

1.執行緒與程序的區別

每個正在系統上執行的程式都是一個程序。每個程序包含一到多個執行緒。執行緒是一組指令的集合,或者是程式的特殊段,他可以在程式裡獨立執行。也可以把它理解為程式碼執行的上下文。
所以執行緒基本是輕量級的程序,它負責在單個程式裡執行任務。通常有作業系統負責多個執行緒的排程和執行。
總結:程序是所有執行緒的集合,而每個執行緒是程序中的一條執行路徑。

2.為什麼要使用多執行緒?

多執行緒主要是提高程式的效率。
例如:迅雷多執行緒下載、資料庫連線池、分批發送簡訊。

3.多執行緒建立方式

3.1第一種繼承Thread類,重寫run方法

class
CreateThread extends Thread {
// run方法中編寫 多執行緒需要執行的程式碼 publicvoid run() { for (inti = 0; i< 10; i++) { System.out.println("i:" + i); } } } publicclass ThreadDemo { publicstaticvoid main(String[] args) { System.out.println("-----多執行緒建立開始-----"); // 1.建立一個執行緒
CreateThread createThread = new CreateThread(); // 2.開始執行執行緒 注意 開啟執行緒不是呼叫run方法,而是start方法 System.out.println("-----多執行緒建立啟動-----"); createThread.start(); System.out.println("-----多執行緒建立結束-----"); } }

3.2第二種實現Runnable介面,重寫run方法

class CreateRunnable implements
Runnable {
@Override publicvoid run() { for (inti = 0; i< 10; i++) { System.out.println("i:" + i); } } } publicclass ThreadDemo2 { publicstaticvoid main(String[] args) { System.out.println("-----多執行緒建立開始-----"); // 1.建立一個執行緒 CreateRunnable createThread = new CreateRunnable(); // 2.開始執行執行緒 注意 開啟執行緒不是呼叫run方法,而是start方法 System.out.println("-----多執行緒建立啟動-----"); Thread thread = new Thread(createThread); thread.start(); System.out.println("-----多執行緒建立結束-----"); } }

3.3第三種使用匿名內部類方式

public static void main(String[] args) {
     System.out.println("-----多執行緒建立開始-----");
     Thread thread = new Thread(new Runnable() {
        public void run() {
            for (int i = 0; i< 10; i++) {
                System.out.println("i:" + i);
            }
        }
     });
     thread.start();
     System.out.println("-----多執行緒建立結束-----");
}
  1. 使用繼承Thread類還是使用實現Runnable介面好?
    使用實現實現Runnable介面好,原因實現了介面還可以繼續繼承,繼承了類不能再繼承。
  2. 啟動執行緒是使用呼叫start方法還是run方法?
    開始執行執行緒 注意 開啟執行緒不是呼叫run方法,而是start方法
    呼叫run知識使用例項呼叫方法。

4.獲取執行緒物件以及名稱

  1. 常用執行緒api方法
    start() —–> 啟動執行緒
    currentThread() —–> 獲取當前執行緒物件
    getID() 獲取當前執行緒ID —–> Thread-編號 該編號從0開始
    getName() —–> 獲取當前執行緒名稱
    sleep(long mill) —–> 休眠執行緒
    Stop() —–> 停止執行緒,
  2. 常用執行緒建構函式
    Thread() —–> 分配一個新的 Thread 物件
    Thread(String name) —–> 分配一個新的 Thread物件,具有指定的 name正如其名。
    Thread(Runable r) —–> 分配一個新的 Thread物件
    Thread(Runable r, String name) —–> 分配一個新的 Thread物件

5.守護執行緒

java中有兩種執行緒:一種是使用者執行緒,另一種是守護執行緒
使用者執行緒是指使用者自定義建立的執行緒,主執行緒停止,使用者執行緒不會停止,互不影響。
守護執行緒當程序不存在或主執行緒停止,守護執行緒也會被停止。
可以使用setDaemon(true) 方法設定為守護執行緒

/**
* 什麼是守護執行緒? 守護執行緒 程序執行緒(主執行緒掛了) 守護執行緒也會被自動銷燬.
*/
public class DaemonThread {
    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) {
                        // TODO: handle exception
                    }
                    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("主執行緒執行完畢!");
    }
}

6.多執行緒的執行狀態

這裡寫圖片描述
執行緒從建立、執行到結束總時處於五個狀態之一:新建轉態、就緒狀態、執行狀態、阻塞狀態及死亡狀態

  1. 新建狀態
    當用new操作符建立一個執行緒時,例如new Thread(r),執行緒還沒有開始執行,此事執行緒處在新建狀態。
    當一個執行緒處於新生轉態時,程式還沒有開始執行執行緒中的程式碼。

  2. 就緒狀態
    一個新建立的執行緒並不自動開始執行,要執行執行緒,必須呼叫執行緒的start()方法。當執行緒物件呼叫start()方法即啟動了執行緒,start()方法建立執行緒執行的系統資源,並排程執行緒執行run()方法。當start()方法返回後,執行緒就處於就緒狀態。
    處於就緒狀態的執行緒並不一定立即執行run()方法,執行緒還必須同其他執行緒競爭CPU時間,只有獲得CPU時間才可以執行執行緒。因為在單CPU的計算機系統中,不可能同時執行多個執行緒,一個時刻僅有一個執行緒處於執行狀態。因此此時可能有多個執行緒處於就緒狀態。對多個處於就緒狀態的執行緒是由Java執行時系統的執行緒排程程式(thread scheduler)來排程的。

  3. 執行狀態
    當執行緒獲取cpu時間後,他才能進入執行狀態,真正開始執行run()方法

  4. 阻塞狀態
    執行緒執行過程中,可能由於各種原因進入阻塞狀態:
    1>執行緒通過呼叫sleep() 進入睡眠轉態
    2>執行緒呼叫一個在I/O上唄阻塞的操作,及該操作在輸入輸出操作完成之前不會返回他的呼叫者
    3>執行緒檢視得到一個鎖,兒該鎖正被其它執行緒持有
    4>執行緒在等某個觸發條件

  5. 死亡狀態
    有兩個原因會導致執行緒死亡:
    1) run()方法正常退出而自然死亡
    2) 一個未捕獲的異常終止了 run() 方法二使執行緒猝死
    為了確定執行緒在當前是否存活著(就是要麼是可執行的,要麼是被阻塞了),需要使用isAlive方法。
    如果是可執行或被阻塞,這個方法返回true,如果執行緒仍舊是new狀態不是可執行的,或者執行緒死亡了,則返回false。

7.執行緒中join()方法作用

當在主執行緒當中執行到t1.join()方法時,就認為主執行緒應該把執行權讓給t1。

需求: 建立一個執行緒,子執行緒執行完畢後,主執行緒才能執行。

Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    try {
                        Thread.sleep(10);
                    } catch (Exception e) {
                    }
                    System.out.println(Thread.currentThread().getName() + "i:" + i);
                }
            }
        });
        t1.start();
        // 當在主執行緒當中執行到t1.join()方法時,就認為主執行緒應該把執行權讓給t1
        t1.join();
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(10);
            } catch (Exception e) {
            }
            System.out.println("main" + "i:" + i);
        }

8.執行緒優先順序的設定

現代作業系統基本採用時分的形式排程執行的執行緒,執行緒分配得到的時間片的多少決定了執行緒使用處理器資源的多少,也對應了執行緒優先順序這個概念。在JAVA執行緒中,通過一個int priority來控制優先順序,範圍為1-10,其中10最高,預設值為5。下面是原始碼(基於1.8)中關於priority的一些量和方法。

class PrioritytThread implements Runnable {
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().toString() + "---i:" + i);
        }
    }
}

public class ThreadDemo4 {
    public static void main(String[] args) {
        PrioritytThread prioritytThread = new PrioritytThread();
        Thread t1 = new Thread(prioritytThread);
        Thread t2 = new Thread(prioritytThread);
        t1.start();
        // 注意設定了優先順序, 不代表每次都一定會被執行。 只是CPU排程會有限分配
        t1.setPriority(10);
        t2.start();
    }
}

9.執行緒Yield方法

Thread.yield()方法的作用:暫停當前正在執行的執行緒,並執行其他執行緒。(可能沒有效果)
yield()讓當前正在執行的執行緒回到可執行狀態,以允許具有相同優先順序的其他執行緒獲得執行的機會。因此,使用yield()的目的是讓具有相同優先順序的執行緒之間能夠適當的輪換執行。但是,實際中無法保證yield()達到讓步的目的,因為,讓步的執行緒可能被執行緒排程程式再次選中。
結論:大多數情況下,yield()將導致執行緒從執行狀態轉到可執行狀態,但有可能沒有效果。

10.執行緒知識強化

1.程序與執行緒的區別?
答:程序是所有執行緒的集合,每一個執行緒是程序中的一條執行路徑,執行緒只是一條執行路徑。
2.為什麼要用多執行緒?
答:提高程式效率
3.多執行緒建立方式?
答:繼承Thread或Runnable 介面。
4.是繼承Thread類好還是實現Runnable介面好?
答:Runnable介面好,因為實現了介面還可以繼續繼承。繼承Thread類不能再繼承。
5.你在哪裡用到了多執行緒?
答:主要能體現到多執行緒提高程式效率。
舉例:分批發送簡訊、迅雷多執行緒下載等。