java多線程五:多線程深入話題(優雅的停止線程)

文章出處 https://www.jianshu.com/p/744c4e65a3b3

文章對應視頻出處:https://developer.aliyun.com/course/1012?spm=5176.10731542.0.0.6ef2d290hxQ4g0

在多線操作之中如果要啓動多線程使用的是Thread類中的start()方法,而如果對於多線程需要進行停止處理,Thread類原本提供了stop()方法,但是對於這些方法從JDK1.2版本就已經廢除了,而且一直到現在也不再建議使用,而除了stop()之外還有幾個方法也被禁用了:

  • 停止多線程:public final void stop​();
  • 銷燬多線程:public void destroy​();
  • 掛起線程:public final void suspend​()、暫停執行;
  • 恢復掛起的線程執行:public final void resume​();
      之所以廢除掉這些方法,主要原因是因爲這些方法可能導致線程死鎖,所以從JDK1.2後開始都不再建議使用了。所以,如果要想實現線程的停止需要通過一種柔和的方式來進行。
    範例:實現線程柔和的停止
public class ThreadDemo {
    public static boolean flag = true;
    public static void main(String[] args) throws Exception {
        new Thread(() -> {
            long num = 0;
            while (flag) {
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "正在運行、num = " + num++);
            }
        }, "執行線程").start();
        Thread.sleep(200);//運行200毫秒
        flag = false;//停止線程
    }
}

 

萬一現在有其他線程去控制這個flag的內容,那麼這個時候對於線程的停止也不是說停就立刻停止的,而是會在執行中判斷flag的內容來完成。

守護線程

  現在假設有一個保鏢,那麼這個保鏢一定是在僱主活着時候進行守護,僱主死了,保鏢就沒用了。所以在多線程中可進行守護線程的定義,也就是說如果現在主線程的程序或者其他線程還在執行的時候,那麼守護線程將一直存在,並且運行在後臺狀態。
  在Thread類中提供有如下的守護線程的操作方法:

  • 設置爲守護線程:public final void setDaemon​(boolean on);
  • 判斷是否爲守護線程:public final boolean isDaemon​();
    範例:使用守護線程
public class ThreadDemo {
    public static void main(String[] args) throws Exception {
        Thread userThread = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "正在運行、x = " + i);
            }
        }, "用戶線程");//完成核心業務
        Thread deamonThread = new Thread(() -> {
            for (int i = 0; i < Integer.MAX_VALUE; i++) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "正在運行、x = " + i);
            }
        }, "守護線程");//完成核心業務
        userThread.start();
        deamonThread.setDaemon(true);//設置爲守護線程
        deamonThread.start();
    }
}
}

  可以發現所有的守護線程都是圍繞在用戶線程的周圍,如果程序執行完畢了,守護線程也就消失了,在整個JVM中最大的守護線程就是GC線程。
  程序執行中GC線程會一直存在,如果程序執行完畢,GC線程也將消失。

volatile關鍵字

  在多線程定義中,volatile關鍵字主要是在屬性上使用的,表示此屬性爲直接數據操作,而不進行副本的拷貝處理。在一些書上就錯誤的理解爲同步屬性了。
  在正常進行變量處理的時候往往會經歷如下的幾個步驟:

  • 獲取變量的數據內容;
  • 爲變量進行數學計算;
  • 將計算後的變量,保存到原始空間之中;
      而如果一個屬性上追加了volatile關鍵字,表示的就是不使用副本,而是直接操作原始變量,相當於節約了拷貝副本、重新保存的步驟。

class MyThread implements Runnable {
    private volatile int ticket = 5;//直接內存操作
    @Override
    public void run() {
        synchronized (this){
            while (this.ticket > 0) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "賣票,ticket = " + this.ticket--);
            }
        }
    }
}
public class ThreadDemo {
    public static void main(String[] args) throws Exception {
        MyThread mt = new MyThread();
        new Thread(mt, "票販子A").start();
        new Thread(mt, "票販子B").start();
        new Thread(mt, "票販子C").start();
    }
}

 

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