1. 程式人生 > >Java筆記-多執行緒之執行緒控制

Java筆記-多執行緒之執行緒控制

執行緒控制

我們已經知道了執行緒的排程,接下來我們就可以使用如下方法物件執行緒進行控制。

1.執行緒休眠

public static void sleep(long millis):讓當前執行緒處於暫停狀態,millis引數毫秒值,即暫停時間。

程式碼演示如下:

1.MyThread.java:

public class MyThread extends Thread {
    public MyThread() {
    }

    public MyThread(String name) {
        super(name);
    }

    @Override
public void run() { for (int i = 0; i < 20; i++) { try { // 執行緒休眠 1000ms 即 1s sleep(1000); System.out.println("我是---->" + getName() + ":" + i); } catch (InterruptedException e) { e.printStackTrace(); } } } }

2.Test.java:

public class Test {
    public static void main(String[] args) {
        MyThread t1 = new MyThread("張飛");
        MyThread t2 = new MyThread("關羽");
        t1.start();
        t2.start();
    }
}

執行緒加入(執行緒強制執行)

public final void join():後面其他執行緒等待,當前執行緒執行完,後面其他執行緒再開始執行。

呼叫必須是在當前執行緒start以後,其他執行緒start之前。

程式碼演示如下:

1.MyThread.java:

public class MyThread extends Thread {
    public MyThread() {
    }

    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            try {
                // 執行緒休眠 100ms
                sleep(100);
                System.out.println("我是---->" + getName() + ":" + i);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

2.Test.java:

public class Test {
    public static void main(String[] args) throws InterruptedException {
        MyThread t0 = new MyThread("劉備");
        MyThread t1 = new MyThread("張飛");
        MyThread t2 = new MyThread("關羽");
        t0.start();
        // 執行緒加入 執行緒強制執行 
        // 執行結果 劉備先買完,然後張飛關羽再多執行緒買
        t0.join();
        t1.start();
        t2.start();
        //如果這樣
        /*
        t1.start();
        t0.start();
        // 執行緒加入 執行緒強制執行 
        // 執行結果 劉備張飛多執行緒買,都買完之後,關羽再買
        t0.join();
        t2.start();
        */
    }
}

3.執行緒禮讓

public static void yield():當前執行的執行緒,執行完畢後會禮讓後面的執行緒。也就是說最好的情況就是每個執行緒都交替執行,沒有連續多次執行同一個執行緒的情況發生。

但是由於執行緒執行具有隨機性,所以該方法並不能保證完全的交替執行,所以說效果並不好,用處較少。

演示程式碼如下:

1.MyThread.java:

public class MyThread extends Thread {
    public MyThread() {
    }

    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        // 執行緒禮讓
        Thread.yield();
        for (int i = 0; i < 20; i++) {
            try {
                // 執行緒休眠 100ms
                sleep(100);
                System.out.println("我是---->" + getName() + ":" + i);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

2.Test.java:

public class Test {
    public static void main(String[] args) throws InterruptedException {
        MyThread t1 = new MyThread("張飛");
        MyThread t2 = new MyThread("關羽");
        t1.start();
        t2.start();
    }
}

4.後臺執行緒(守護執行緒)

public final void setDaemon(boolean on):被守護執行緒如果執行結束,則守護執行緒直接終止,不繼續執行任何一行程式碼。

注意:守護執行緒要在聲明後,和start()前宣告。否則報錯!

演示程式碼如下:

劉關張三兄弟,一起上陣殺敵。 目的:一旦劉備(主公)死了,關羽張飛就不再殺敵直接被俘虜了。

1.MyThread.java:

public class MyThread extends Thread {
    public MyThread() {
    }

    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        System.out.println(getName() + "--->已經到達戰場!");
        // 執行緒禮讓
        Thread.yield();
        for (int i = 0; i < 20; i++) {
            try {
                // 執行緒休眠 100ms
                sleep(100);
                System.out.println(getName() + "開始對抗第 " + i + " 個敵人");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(getName() + "--->戰死了!!!!");
    }
}

2.Test.java:

public class Test {
    public static void main(String[] args) throws InterruptedException {
        MyThread t1 = new MyThread("張飛");
        MyThread t2 = new MyThread("關羽");
        // 設定後臺執行緒 守護執行緒
        t1.setDaemon(true);
        t2.setDaemon(true);
        t1.start();
        t2.start();
        System.out.println("劉備----->到達戰場!!!!");
        for (int i = 0; i < 10; i++) {
            // 為了明顯讓主執行緒也休眠
            Thread.sleep(100);
            System.out.println("劉備開始對抗第 " + i + " 個敵人");
        }
        System.out.println("劉備戰死了!!!!");
    }
}

5.中斷執行緒

例子:劉關張三兄弟都困了,劉備先挺不住睡覺了,關羽張飛看到就也睡覺了,但是劉備先醒了,看到他們兩個在睡覺,就把他們兩個叫醒了。

public final void stop():不推薦使用,此方法太血腥。直接中斷執行緒,後面程式碼不執行了。 例子中,就是劉備醒了後看到兩兄弟在睡覺,很生氣,叫人把他們弄死了。兩兄弟再也睡不醒了。

public void interrupt():不推薦使用,此方法太暴力,直接給當前執行緒丟擲了一個異常。 Interrupt()方法會向子執行緒丟擲一個InterruptedException異常,異常結束了子執行緒的休眠。

推薦使用的方法: 像停止一個高速旋轉的輪子一樣,慢慢停止旋轉。 程式碼:一般子執行緒裡面都是長迴圈或耗時操作,只要把長迴圈或耗時操作的狀態改為不再迴圈,則慢慢停止。 推薦使用:布林值,控制迴圈停止,溫和終止方式。

演示程式碼如下:

1.MyThread.java:

public class MyThread extends Thread {
    public MyThread() {
    }

    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        System.out.println(getName() + "--->開始睡覺!!!");
        try {
            for (int i = 0; i < 10 && Flag.FLAG; i++) {
                // 執行緒休眠 1000ms
                sleep(1000);
                System.out.println(getName() + "--->正在睡覺--" + i);
            }
        } catch (InterruptedException e) {
            System.out.println(getName() + "--->被一棒子打醒!");
        }
        System.out.println(getName() + "--->睡醒了!!!");
    }
}

2.Flag.java:

public class Flag {
    //僅僅用來判斷迴圈是否繼續
    public static boolean FLAG = true;
}

3.Test.java:

public class Test {
    public static void main(String[] args) throws InterruptedException {
        MyThread t1 = new MyThread("張飛");
        MyThread t2 = new MyThread("關羽");
        t1.start();
        t2.start();
        System.out.println("劉備----->開始睡覺!!!!");
        // 為了明顯讓主執行緒也休眠
        Thread.sleep(3000);
        System.out.println("劉備睡醒了!!!!");
        // 使用boolean值控制迴圈停止,溫和
        // 劉備睡醒後二人也能再睡短短的一會兒,然後被溫柔的叫醒
        Flag.FLAG = false;
        // 太暴力,一棒子打醒了二人
        // t1.interrupt();
        // t2.interrupt();
        // 太血腥,直接弄死了二人,再也睡不醒了
        // t1.stop();
        // t2.stop();
    }
}