多線程編程三-線程的狀態切換

目錄

 

1 線程停止

2 線程讓步

3 線程加入

4 線程通信(wait和notify)


1 線程停止

Thread的stop方法已過時,通常情況下需要程序員自己寫一些方法讓線程停止。
通常可以在線程內部做一個flag標識,通過flag判斷線程是否繼續執行

public class ThreadStop {
    public static void main(String[] args){
        RunnableThread rt = new RunnableThread();
        Thread thr = new Thread(rt);
        thr.start();
        for(int i = 1; i <= 20; i++){
            if(i == 10){
                rt.stop();
            }
            System.out.println("主線程:"+i);
        }
    }
}

class RunnableThread implements Runnable{
    private volatile boolean flag = true;
    int i = 0;
    @Override
    public void run() {
        while(flag){
            i++;
            System.out.println("RunnableThread執行第"+i+"次");
        }
    }
    
    public void stop(){
        this.flag = false;
        System.out.println("RunnableThread線程停止");
    }
}

2 線程讓步

調用Thread.yield();的當前線程會讓出CPU資源,然後重新參與資源競爭。競爭結果是有可能繼續佔用CPU資源,有可能不是

@Test
public void testYield() throws InterruptedException, ExecutionException {
    RunnableThread runnableThread = new RunnableThread();
    Thread thr = new Thread(runnableThread);
    thr.start();
    for (int i = 1; i <= 100; i++) {
        System.out.println(i);
        // 主線程每執行10次,讓步一次
        if (i % 10 == 0) {
            Thread.yield();
        }
    }
}

class RunnableThread implements Runnable {
    boolean flag = true;
    int i = 0;
    @Override
    public void run() {
        while (flag) {
            System.out.println(Thread.currentThread().getName() + "執行" + (i ++) + "次");
        }
    }
}


觀察輸出結果可以發現每次讓步後有可能主線程繼續運行,有可能切換到子線程運行

3 線程加入

@Test
public void testJoin() throws InterruptedException, ExecutionException {
    RunnableThread runnableThread = new RunnableThread();
    RunnableThread runnableThread2 = new RunnableThread();
    Thread thr = new Thread(runnableThread, "子線程一");
    Thread thr2 = new Thread(runnableThread2, "子線程二");
    thr.start();
    thr2.start();
    for (int i = 1; i <= 100; i++) {
        System.out.println(i);
        // 主線程執行10次後然子線程加入
        if (i == 10) {
            thr.join();
        }
    }
}

class RunnableThread implements Runnable {
    boolean flag = true;
    int i = 0;
    @Override
    public void run() {
        while (flag) {
            System.out.println(Thread.currentThread().getName() + "執行" + (i ++) + "次");
            if (i == 300) {
                break;
            }
        }
    }
}

觀察輸出結果可以發現主線程輸出10後兩個子線程交替執行。直到兩個子線程執行完畢,主線程才繼續運行

4 線程通信(wait和notify)

wait和notify是Object類的方法,某個對象執行wait或notify的時候當前線程一定要先獲取到synchronized鎖,否則會報IllegalMonitorStateException,有興趣的同學可以研究一下相關的JIN方法
實現功能:創建兩個線程,交替輸出各自線程的名字

/**
 * 當前標誌位
 */
private volatile int flag = 0;

/**
 * 定義一個鎖
 */
private final String lock = "";

@Test
public void testWaitAndNotify() throws InterruptedException, ExecutionException {
    // 線程一執行標誌位是0,下個線程(線程二)執行標誌位是1
    RunnableThread runnableThread = new RunnableThread(0, 1);
    // 線程二執行標誌位是1,下個線程(線程一)執行標誌位是0
    RunnableThread runnableThread2 = new RunnableThread(1, 0);
    Thread thr = new Thread(runnableThread, "線程一");
    Thread thr2 = new Thread(runnableThread2, "線程二");
    thr.start();
    thr2.start();
    TimeUnit.HOURS.sleep(1);
}

class RunnableThread implements Runnable {

    /**
     * 當前線程執行標識
     */
    private volatile int symbol;

    /**
     * 下個線程執行標識
     */
    private volatile int next;

    public RunnableThread(int symbol, int next) {
        this.symbol = symbol;
        this.next = next;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (lock) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException ignore) {}
                if (flag != symbol) {
                    try {
                        // 調用wait和notify的方法一定要是synchronized鎖住的對象
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                if (flag == symbol) {
                    System.out.println(Thread.currentThread().getName());
                    flag = next;
                    // 調用wait和notify的方法一定要是synchronized鎖住的對象
                    lock.notify();
                }
            }
        }
    }
}


這樣我們就可以在控制檯看到線程一,線程二交替輸出

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章