1. 程式人生 > >【java多執行緒】守護執行緒、執行緒停止、volatile的深入瞭解

【java多執行緒】守護執行緒、執行緒停止、volatile的深入瞭解

文章目錄

執行緒的優雅停止

      在多執行緒的操作之中如果要啟動多執行緒肯定使用的Thread類中的start()方法,而對於咱們的多執行緒需要進行停止處理,原來的Thread類提供有stop()方法,但是對於這些方法從JDK1.2版本就已經將其廢除了,而且一直到現在也不建議出現在你的程式碼中,而除了stop()之外還有幾個方法也別禁用了:

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

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

守護執行緒

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

  • 設定守護執行緒:public final void setDaemon(boolean on);
  • 判斷是否為守護執行緒:public final Boolean isDaemon();
    範例:使用守護執行緒
public class ThreadD {

    public static void main(String[] args) throws InterruptedException {
         Thread userThread = new Thread(( ) -> {
             for(int x = 0 ; x < 10 ; x ++){
                     try {
                         Thread.sleep(100);
                     } catch (InterruptedException e) {
                         e.printStackTrace();
                     }
                     System.out.println(Thread.currentThread().getName() + "正在執行 x = " + x);
                 }
         },"使用者執行緒");
        Thread daemonThread = new Thread(( ) -> {
            for(int x = 0 ; x < Integer.MAX_VALUE ; x ++){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "正在執行 x = " + x);
                }
        },"守護執行緒");
         daemonThread.setDaemon(true); //設定為守護執行緒
        userThread.start();
        daemonThread.start();
    }
}

      可以發現所有的守護執行緒是圍繞在使用者執行緒周圍,如果程式執行完畢了,守護執行緒也就消失了。而在JVM找那個最大的守護執行緒就是GC執行緒。
      程式執行中GC執行緒會一直存在,如果程式執行完畢,那麼GC執行緒也將消失。

volatile關鍵字

      在多執行緒的定義之中,volatile是在屬性定義上使用的,表示此屬性為直接資料操作,而不進行副本的拷貝處理,這樣的話在一些書上就將其錯誤的理解為同步屬性了。
      在正常進行變數處理的時候往往會經歷如下幾個步驟:

  • 獲取變數原有的資料內容副本;
  • 利用副本為變數進行數學計算;
  • 將計算後的變數,儲存到原始空間之中;

而如果一個屬性追加了volatile關鍵字,表示的就是不使用副本,而是直接操作原始變數,相當於節約了:拷貝副本、重新儲存的步驟。
流程圖如下:
在這裡插入圖片描述
面試題:請解釋volatile與synchronized的區別?

  • volatile主要的屬性上使用,而synchronized是在程式碼塊與方法上使用的;
  • volatile無法描述同步的處理,它只是一種直接記憶體的處理,避免了副本的操作,而synchronized是實現同步的。