Java(8-1)

不知道多久了,這次該說多線程了。
Part 1如何設置一個多線程:
①將任務代碼移到實現了Runnable接口的類的run方法中。這個接口非常簡單,只有一個方法:

public interface Runnable
{
    void run();
}
//這裏由於Runnable是一個函數式接口,所以我們可以使用lambda表達式。
//當然,現在來說公司中用的更多地是匿名類來實現這個

②由Runnable創建一個Thread(英文就是線程的意思)對象:

Thread t = new Thread(t);

③啓動線程:

t.start()

就這麼簡單!另外提一下,我們也可以通過構建一個Thread類的子類來定義一個線程,然後調用statr方法,例如:

class MyThread extends Thread
{
    public void run()
    {
        //code
    }
}

但是這種方法已經不推薦了!應該將要並行運行的任務和運行機制解耦合。如果有很多任務,要爲每個任務創建一個獨立的線程,那付出的代價太大了!還有一點,不要調用Thread的run方法,這樣只會執行同一個線程中的人物,而不會啓動新線程!
看一個銀行系統的例子:

public class BankTest{
    public static final int NACCOUNTS = 100;
    public static final double INITIAL_BALANCE = 1000;
    public static final double MAX_AMOUNT = 1000;
    public static final int DELAY = 10;

    public static void main(String[] args)
    {
        Bank bank = new Bank(NACCOUNTS,INITIAL_BALANCE);
        for(int i = 0;i < NACCOUNTS;i++)
        {
            int fromAccount = i;
            Runnable r = new Runnable(){
                try{
                    while(true){
                        int toAccount = (int)(bank.size() * Math.random());
                        double amount = MAX_AMOUNT * Math.random();
                        bank.transfer(fromAccount,toAccount,amount);
                        Thread.sleep((int)(DELAY * Math.random()));
                    }
                }
                catch(InterruptedException e){}
            };
            Thread t = new Thread(r);
            t.start();
        }
    }
}

Part2 關於中斷線程
我們先看下線程終止的條件:當線程的run方法執行方法體中最後一條語句時,並經由執行return語句返回時,或者出現了在方法中沒有捕獲的異常時,線程將終止!

在早期版本中,Java還有一個stop方法,線程可以調用它終止線程,但是現在已經棄用了!所以Java中目前沒有可以強制線程終止的方法,然而,我們有interrupt方法,可以用來請求終止線程。

當對一個線程調用interrupt方法時,線程的中斷狀態狀態將被置位。這是每一個線程都會有的一個boolea類型標誌,每個線程都應該不斷地去檢查這個Boolean標誌,以判斷線程是否被中斷。

我們要想清楚中斷狀態位是否被置位,首先調用靜態的Thread.currentThread方法獲取當前線程,然後調用isInterrupted方法:

while(!Thread.currentThread().isInterrupted() && more work to do)
{
    do more work
}

但是,如果線程已經被阻塞,就無法檢測中斷狀態!這就是產生 InterruptedException異常的地方(劃重點!!!) 當在一個被阻塞的線程(調用sleep或者wait)上調用interrupt方法時,阻塞調用將會被 Interrupted Exception異常中斷。

不過,被異常中斷的線程並不意味着這個線程應該被終止。中斷一個線程可能只是引起CPU的注意。被中斷的線程可以決定如何響應中斷。某些線程很重要,所以可能在處理完異常後又繼續執行,而不理會中斷。但是,更普遍的是,線程將簡單地將中斷作爲一個終止請求。這種線程的run方法具有如下形式:

Runnable r = new Runnable(){
    try{
    ...
        while(!Thread.currentThread().isInterrupted()&&more work to do){
            do more work
        }
    }
    catch(InterruptedException e){
    // thread was interrupted during sleep or wait
    }
    finally{
        cleanup,if required
    }
    //exiting the run method treminates the thread
};

當我們的代碼每次工作迭代之後都調用sleep方法(或者其他的可中斷方法),isInterrupted檢測既沒有必要也沒有用處。
還有!
如果在中斷狀態被位時調用sleep方法,線程不會休眠。相反,線程會清除這一狀態!並拋出InterruptException。因此,如果你的循環調用sleep,不會檢測中斷狀態。相反,你要捕獲InterruptException異常:

Runnable r = new RunnableI(){
    try{
    ...
        while(more work to do){
            do more work
            Thread.sleep(delay);
        }
    }
    catch(InterruptedException e){
    }finally{
        cleanup,if required
    }
};

Tip:注意下interrupted和isInterrupted的區別 。 P634中有提到。

《java核心技術》的作者認爲,將InterruptedException異常被抑制在很低層次(就像上面那樣),是不值得贊同地,作者認爲有兩種合理的選擇:
1.在catch子句中調用Thread.currentThread().interrupt()來設置中斷狀態。於是,調用者可以對其進行檢測:

    {
        ...
        try{sleep(delay);}
        catch(InterruptedException e){Thread.currentThread().interrupt();}
    }

2.更好的方法是用throws InterruptedException標記你的方法,不採用try語句塊捕獲異常。於是,調用者(或者,最終的run方法)可以捕獲這一異常。

void mySubTask() throws InterruptedException
{
...
x.sleep(delay);
...
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章