玩轉Java高併發編程

進程和線程的區別

  • 進程是資源分配的最小單位,線程是CPU調度的最小單位
  • 進程是一個資源的容器,爲進程裏的所有線程提供共享資源,是對程序的一種靜態描述,線程是計算機最小的調度和運行單位,是對程序的一種動態描述,一靜一動,正好組成了完整的程序
    線程和進程的區別是什麼?

線程的生命週期

創建線程的方式

一、繼承Thread類創建線程類

(1)定義Thread類的子類,並重寫該類的run方法,該run方法的方法體就代表了線程要完成的任務。因此把run()方法稱爲執行體。

(2)創建Thread子類的實例,即創建了線程對象。

(3)調用線程對象的start()方法來啓動該線程。

二、通過Runnable接口創建線程類

(1)定義runnable接口的實現類,並重寫該接口的run()方法,該run()方法的方法體同樣是該線程的線程執行體。

(2)創建 Runnable實現類的實例,並依此實例作爲Thread的target來創建Thread對象,該Thread對象纔是真正的線程對象。

(3)調用線程對象的start()方法來啓動該線程。

這種方法運用了模板策略:

定義一個算法流程的骨架,把一些可變節點延遲到具體的子類中去執行, 把邏輯實例和線程分開,每個線程共享同一個邏輯,是一種有效減少程序中類的數量的開發模式

//若不重寫run方法或傳遞runnable對象,則不會運行邏輯
Thread()
//Allocates a new Thread object. 
Thread(String name)
//Allocates a new Thread object.指定線程名,默認線程名‘Thread-計數’
Thread(Runnable target)
//Allocates a new Thread object.傳遞Runnable接口對象
Thread(Runnable target, String name)
//Allocates a new Thread object.指定線程名,默認線程名‘Thread-計數’

//線程組是爲了更好的統一對線程管理,比如同時關閉組內所有線程
Thread(ThreadGroup group, Runnable target)
//Allocates a new Thread object.指定線程組,默認線程組爲父線程的組
Thread(ThreadGroup group, Runnable target, String name)
//Allocates a new Thread object so that it has target as its run object, has the specified name as its name, and belongs to the thread group referred to by group.
Thread(ThreadGroup group, Runnable target, String name, long stackSize)
//Allocates a new Thread object so that it has target as its run object, has the specified name as its name, and belongs to the thread group referred to by group, and has the specified stack size.
//stacksize是指線程佔用的棧深(遞歸溢出的大小),棧深越大,棧內線程可用數越少
//受操作系統影響,有些平臺上未必有用
Thread(ThreadGroup group, String name)
//Allocates a new Thread object.

守護線程

void	setDaemon(boolean on)
//Marks this thread as either a daemon thread or a user thread.

在Java中有兩類線程:User Thread(用戶線程)、Daemon Thread(守護線程),守護線程會伴隨創建線程結束而結束。這個特點使用妥當可以用來結束和釋放線程,不妥當會出現線程莫名中斷或退出

Join方法

主線程進入阻塞狀態,讓“主線程”等待“子線程”結束之後才能繼續運行。
注意 是調用join()方法的當前線程進入阻塞,而不是調用的線程對象進入阻塞

// 主線程
public class Father extends Thread {
    public void run() {
        Son s = new Son();
        s.start();
        s.join();
        ...
    }
}
// 子線程
public class Son extends Thread {
    public void run() {
        ...
    }
}

Interrupt方法

那麼不能直接把一個線程搞掛掉, 但有時候又有必要讓一個線程死掉, 或者讓它結束某種等待的狀態 該怎麼辦呢?一個比較優雅而安全的做法是:使用等待/通知機制或者給那個線程一箇中斷信號, 讓它自己決定該怎麼辦。

  • 調用thread.interrupt(),會告知被調用線程中斷狀態爲true.
  • 對於非阻塞中的線程, 只是中斷狀態改變爲true
  • 對於阻塞狀態中的線程, 比如等待在這些函數上的線程, Thread.sleep(), Object.wait(), Thread.join(), 這個線程收到中斷信號後, 會拋出InterruptedException,同時中斷狀態改變爲false,因爲拋出異常意味着該線程已被打斷。
  • 在使用synchronized關鍵字獲取鎖的過程中不響應中斷請求,即線程interrupt後仍需要爭搶鎖才能響應中斷請求。如果這對程序是一個問題,可以使用顯式鎖,即java中Lock接口,它支持以響應中斷的方式獲取鎖。

獲取中斷狀態

  • Thread.currentThread().interrupt();該方法返回爲true的時候,會將中斷狀態重置爲false
  • Thread.isInterrupted();該方法不會重置中斷狀態,且爲靜態方法

注意事項:Thread.join(),中斷信息發送的不是給Thread,而是執行Thread.join()的線程

線程結束

線程結束不推薦stop()方法,並且該方法已明確過時。

如何優雅的結束線程

1. 設一個boolean類型的標誌,並通過設置這個標誌爲true或false來控制while循環是否退出

class Demo {
	private class ThreadSafe extends Thread {
	    @Override
	    public void run() { 
	        while (exit){
	            //do something
	        }
	    } 
	}
	private void shutDown(){
		exit = false;
	}
}

2. 捕獲異常+中斷狀態標誌判斷

public class ThreadSafe extends Thread {
    public void run() { 
        while (!isInterrupted()){ //非阻塞過程中通過判斷中斷標誌來退出
            try{
                Thread.sleep(5*1000);//阻塞過程捕獲中斷異常來退出
            }catch(InterruptedException e){
                e.printStackTrace();
                break;//捕獲到異常之後,執行break跳出循環。
            }
        }
    } 
}

2. 守護線程強制中斷退出

因爲有可能程序在中間阻塞,無法執行首位置的判斷語句,因此需要一個強制退出的方案

public class ThreadService {
    private Thread execuateThread;
    private boolean isFinished;
    private Long currentTimeMillis;
    public void excute(Thread thread){
        execuateThread = new Thread(){
            @Override
            public void run() {
                isFinished = false;
                thread.setDaemon(true);
                thread.start();
                try {
                    thread.join();
                } catch (InterruptedException e) {
                    System.out.println("線程超時被打斷");
                }
                isFinished = true;
                System.out.println("線程執行完成");;
            }
        };
        execuateThread.start();
    }
    //等待mill毫秒後若線程還在運行則將其中斷
    public void stop(long mill){
        currentTimeMillis = System.currentTimeMillis();
        while (!isFinished){
            if(System.currentTimeMillis()-currentTimeMillis>mill){
                execuateThread.interrupt();
                break;
            }
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章