多線程之啓動,中止,及其他

啓動線程

1.Runnable是Thread執行的邏輯
2.CallableFutureTask也是Thread要執行的邏輯,只是封裝了獲取結果的功能
因此: 啓動線程的方式只有一種: new Thread().start();

終止線程

1.stop(不建議使用)

示例代碼:

public class Demo_Stop {

    public static void main(String[] args) throws InterruptedException {
        MyThread thread = new MyThread();
        thread.start();

        // 休眠1秒,確保i變量自增成功
        Thread.sleep(1000);
        thread.stop();

        // 確保線程已經終止
        while (thread.isAlive()) {}
        // 輸出結果
        thread.print();
    }
}

class MyThread extends Thread {
    private int i = 0, j = 0;

    @Override
    public void run() {
        synchronized (this) {
            ++i;
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ++j;
        }
        System.out.println("鎖釋放。。。");
    }

    public void print() {
        System.out.println("i=" + i + " j=" + j);
    }
}

打印結果:
在這裏插入圖片描述
需要的輸出結果應該是i=0 j=0;
stop方法沒有保證同步代碼看塊中的數據一致性, 出現了線程安全問題

2.interrupt

示例代碼:

public static void main(String[] args) throws InterruptedException {
        Thread workThread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (!Thread.currentThread().isInterrupted()) {
                    System.out.println("運行中");
                    try {
                        Thread.sleep(100L);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        //將擦除掉的isInterrupted狀態補上
                        Thread.currentThread().interrupt();
                    }
                }
            }
        });
        workThread.start();
        Thread.sleep(3000L);
        workThread.interrupt();
    }

注意點:

1.interrupt方法並不會中斷線程,只是打上了中斷標記

示例代碼:

public static void main(String[] args) throws InterruptedException {

        //開啓一個線程
        Thread testThread = new Thread(){
            @Override
            public void run() {
                while(true){
                    System.out.println("isInterrupted:" + Thread.currentThread().isInterrupted());
                    System.out.println("state:" + Thread.currentThread().getState());
                }
            }
        };

        testThread.start();
        Thread.sleep(2000);

        //調用interrupt方法,不會改變線程狀態
        //並不會讓線程退出,只是做了一個interrupt標記
        testThread.interrupt();
    }

輸出結果:
在這裏插入圖片描述
可以看到,在sleep2秒後,isInterrupted的狀態值由false變爲了true

2.如果該線程在調用 wait(),wait(long)方法,join() 、 join(long, int) 、join(long, int)、sleep(long, int)或sleep(long, int)等方法後,處於WAITING、Timed Waiting狀態時,在該線程被調用interrupt方法後,線程的WAITING、Timed Waiting狀態將被清除,並拋出InterruptedException異常。

示例代碼:

public static void main(String[] args) throws InterruptedException {
        Thread testThread = new Thread(){
            @Override
            public void run() {
                while (true){
                    try {
                        System.out.println("running...");
                        Thread.sleep(1000L);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        /*
                        當線程處於 Waiting、TimedWaiting狀態,
                        執行interrupted方法後,會從Waiting、TimedWaiting中退出
                        並且isInterrupted=true的信號被擦除
                         */
                        System.out.println(Thread.currentThread().getState());
                        System.out.println("isInterrupted:" + Thread.currentThread().isInterrupted());
                    }
                }
            }
        };
        
        testThread.start();
        Thread.sleep(1000);
        testThread.interrupt();
    }

打印結果:
在這裏插入圖片描述

3.如果目標線程是被I/O 或者NIO中的Channel所阻塞,同樣,I/O操作會被中斷或者返回特
殊異常值。

4.park()\parkNanos方法執行後,線程也處於 WAITING、Timed Waiting,也會被喚醒,但是不會拋異常,且有很詭異的情況發生。

示例代碼:

public static void main(String[] args) throws InterruptedException {
        Thread testThread = new Thread(new Runnable() {
            @Override
            public void run() {
                while(true){
                    LockSupport.park();
                    System.out.println("ing...");
                }
            }
        });
        
        testThread.start();

        Thread.sleep(1000L);
        testThread.interrupt();

        System.out.println("============end=============================");

    }

打印結果
在這裏插入圖片描述

deamon線程

定義:

守護線程
是指在程序運行的時候在後臺提供一種通用服務的線程,
進程結束時,會殺死所有守護線程。

注意點:

1.在Daemon線程中產生的新線程也是Daemon的
2.不能把正在運行的常規線程設置爲守護線程,thread.setDaemon(true)必須在thread.start()之前設置,否則會跑出一個IllegalThreadStateException異常。
3.守護線程它會在任何時候甚至在一個操作的中間發生中斷,因此應該永遠不去訪問固有資源,如文件、數據庫等等

CountDownLatch倒計時器

作用:

countDownLatch可以使一個線程等待其他線程各自執行完畢後再執行。

示例代碼:

public class Demo_CountDownLatch {

    static AtomicLong num = new AtomicLong(0);

    public static void main(String args[]) throws InterruptedException {

        CountDownLatch ctl = new CountDownLatch(10);

        for (int i=0; i< 10; i++){
            new Thread(){
                @Override
                public void run() {
                    for (int j=0; j< 1000; j++){
                        num.getAndIncrement();
                    }
                    ctl.countDown();
                }
            }.start();
        }

        //設置開關,設置門栓
        ctl.await();
        System.out.println(num.get());
    }
}

Semaphore計數信號量

作用:

常用於限制可以訪問某些資源(物理或邏輯的)線程數目。
是一種用來控制併發量的共享鎖。

示例代碼:

public class Demo_Semaphore {

    public static void main(String args[]){

        Semaphore sp = new Semaphore(10);

        //短時間發送1000個請求,併發會很高,數據庫會受不了
        for (int i=0; i<1000; i++){
            new Thread(){
                @Override
                public void run() {
                    try {
                        sp.acquire();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    //模擬DB查詢
                    queryDb("localhost:3306");
                    sp.release();
                }
            }.start();
        }

    }
    //發送一個HTTP請求
    public static void queryDb(String uri)  {
        System.out.println("query===>: " + uri);
        // 類似sleep的作用
        LockSupport.parkNanos(1000 * 1000 * 1000);
    }
}

CyclicBarrier循環柵欄

作用:

可以循環利用的屏障

示例代碼:

public class Demo_CyclicBarrier {
    public static void main(String[] args) {

        CyclicBarrier barrier  = new CyclicBarrier(5,// 柵欄一次通過的請求數
                new Runnable() {
                    @Override
                    public void run() {
                        System.out.println(">>> 這是一個柵欄。。。");
                    }
                });

        //傳入一個Runnable,打印柵欄
        for (int i=0; i< 100; i++){
            new Thread(){
                @Override
                public void run() {
                    try {
                        barrier.await();    //
                        System.out.println("請求...");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                }
            }.start();
            LockSupport.parkNanos(1000 * 1000 * 1000L);
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章