I want to fly higher
          programming Explorer
          posts - 114,comments - 263,trackbacks - 0
          1.很多人經常會用錯interrupt方法,直接看例子
          package com.landon.mavs.example.concurrent;

          import java.util.concurrent.LinkedBlockingQueue;
          import java.util.concurrent.TimeUnit;

          import org.slf4j.Logger;
          import org.slf4j.LoggerFactory;

          /**
          *
          * interrupt容易使用出錯的例子
          *
          * <pre>
          * 1.如何結束BadRunnable這樣的任務.即沒有任務結束條件來保證可以正常關閉它.使用interrupt沒有作用,其不會中斷正在運行的線程
          * 2.結論:任務最好不要這樣寫,否則無法正常安全的關閉線程.通常需要在while()中指定任務結束條件如設置volatile變量或者判斷當前線程是否已中斷等或者通過投遞結束消息方式(消息隊列)等
          * </pre>
          *
          * <p>
          * <a href=
          * "http://docs.oracle.com/javase/6/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html"
          * >為何Thread#stop/resume/suspend被棄用</a>
          * <p>
          *
          * @author landon
          *
          */

          public class InterruptePuzzleExample {
             
          private static final Logger LOGGER = LoggerFactory
                      .getLogger(InterruptePuzzleExample.class);

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

                 
          // Thread thread = new Thread(new BadRunnable());

                 
          // thread.start();
                 
          // 執行interrupt,試圖終止無限循環的任務-徒勞
                 
          // thread.interrupt();

                  VolatileRunnable volatileTask = new VolatileRunnable();
                  Thread volatileThread = new Thread(volatileTask);
                  volatileThread.start();

                 
          // 主線程暫停5s
                  Thread.sleep(5 * 1000);
                 
          // 停止任務,結束volatileThread,在主線程置stopFlag(所以用volatile)
                  volatileTask.stop();

                  LOGGER.debug("VolatileRunnable end.");

                  Thread thread2 = new Thread(new InterruptedRunnbale());
                  thread2.start();

                 
          // 主線程暫停1秒
                  Thread.sleep(1 * 1000);
                 
          // 調用interrupte結束任務->直接中斷處于sleep的任務
                  thread2.interrupt();

                  LOGGER.debug("main_thread2 isInterrupted:" + thread2.isInterrupted());

                  QueueThread qt = new QueueThread();
                  qt.start();

                 
          for (int i = 1; i < 5; i++) {
                      qt.offerMessage(new QueueMessage(i));
                  }


                 
          // 準備停止qt
                  qt.prepareDispose();

              }


             
          private static class BadRunnable implements Runnable {

                  @Override
                 
          public void run() {
                      LOGGER.debug("BadRunnable begin.");

                     
          // 無限循環
                      while (true) {
                      }

                  }


              }


             
          private static class VolatileRunnable implements Runnable {
                 
          // 指定volatile(更新即可視) 停止標識
                  private volatile boolean stopFlag;

                 
          public void stop() {
                      stopFlag = true;
                  }


                  @Override
                 
          public void run() {
                      LOGGER.debug("VolatileRunnable begin.");

                     
          while (!stopFlag) {
                      }

                  }

              }


             
          private static class InterruptedRunnbale implements Runnable {

                  @Override
                 
          public void run() {
                      LOGGER.debug("InterruptedRunnbale begin.");

                     
          // 這里判斷調用當前是否已被打斷做判斷
                      while (!Thread.currentThread().isInterrupted()) {
                         
          try {
                             
          // 用sleep替代業務邏輯的耗時,可被打斷
                              TimeUnit.SECONDS.sleep(3);
                          }
          catch (InterruptedException e) {
                              LOGGER.debug("InterruptedRunnbale is interrupted.");

                             
          // 參考Interrupt
                             
          // API.類似調用如wait/join/sleep等方法時會收到InterruptedException且中斷狀態被清除
                              LOGGER.debug("after catch InterruptedException,thread2 isInterrupted:"
                                     
          + Thread.currentThread().isInterrupted());
                             
          // 因為中斷狀態被清除了.所以這次要再次調用interrupt.設置中斷狀態,然后任務從循環跳出.線程結束
                              Thread.currentThread().interrupt();
                              LOGGER.debug("after again execute interrupt,thread2 isInterrupted:"
                                     
          + Thread.currentThread().isInterrupted());
                          }

                      }

                  }

              }


             
          private static class QueueThread extends Thread {
                 
          // 阻塞消息隊列
                  private LinkedBlockingQueue<QueueMessage> queue = new LinkedBlockingQueue<InterruptePuzzleExample.QueueMessage>();
                 
          // 因為這里通過投遞內部消息方式,即在內部單線程執行.所以不用volatile
                  private boolean stopFlag;

                  @Override
                 
          public void run() {
                      LOGGER.debug("QueueThread begin.");

                     
          while (!stopFlag) {
                         
          try {
                              QueueMessage msg = queue.take();

                             
          if (msg != null) {
                                  LOGGER.debug("QueueThread process msg:" + msg);

                                 
          // -1表示停止消息(注:因為是QueueMessage內部使用,可以直接訪問private屬性)
                                  if (msg.msgType == -1) {
                                      dispose();
                                  }

                              }


                          }
          catch (InterruptedException e) {
                              LOGGER.debug("QueueMessage is interrupted.take is notify.");
                          }

                      }

                  }


                 
          public void offerMessage(QueueMessage msg) {
                      queue.offer(msg);
                  }


                 
          public void dispose() {
                      stopFlag = true;
                     
          // 這里interrupt可省略,因為既然執行到了dispose,則此時一定未阻塞
                     
          // interrupt();
                  }


                 
          // 準備銷毀,由外部線程進行調用
                  public void prepareDispose() {
                      LOGGER.debug("QueueThread prepare dispose.");
                      offerMessage(new QueueMessage(-1));
                  }

              }


             
          private static class QueueMessage {
                 
          // 消息類型
                  private int msgType;

                 
          public QueueMessage(int type) {
                      msgType = type;
                  }


                  @Override
                 
          public String toString() {
                     
          return "QueueMessage [msgType=" + msgType + "]";
                  }


              }

          }



          2.很多人經常分不清interrupted和isInterrupted兩個方法的區別,看例子
          package com.landon.mavs.example.concurrent;

          import org.slf4j.Logger;
          import org.slf4j.LoggerFactory;

          /**
          *
          * 使用Thread#interrupted/Thread#isInterrupted
          *
          * <pre>
          * 1.個人認為interrupted方法是返回之前的中斷狀態并清除中斷狀態 2.而isInterrupted只是返回線程的中斷狀態而已
          * 3.而對于interrupt方法
          * ,對于諸如可拋出InterruptedException的一些方法,線程收到InterruptedException后會清除中斷狀態
          * ;反之則會設置狀態中斷{仔細參考Thread#interrupt的api doc}{@link InterruptThread3}}
             *【landon認為因阻塞的線程被interrupt后,雖然是收到了異常,但是卻中斷了阻塞,其實是可以繼續運行的!所以會清除中斷狀態】
          * </pre>
            * <pre>
            *  if (Thread.interrupted())  // Clears interrupted status!
            *      throw new InterruptedException();
            * </pre>
          *
          * <pre>
          * public boolean isInterrupted() {
          *     return isInterrupted(false);
          * }
          *
          * 靜態方法->針對當前調用線程
          * public static boolean interrupted() {
          *     return currentThread().isInterrupted(true);
          * }
          *
          * private native boolean isInterrupted(boolean ClearInterrupted);
          * </pre>
          *
          * @author landon
          *
          */

          public class ThreadInterruptedExample {
             
          private static final Logger LOGGER = LoggerFactory
                      .getLogger(ThreadInterruptedExample.class);

             
          public static void main(String[] args) throws Exception {
                  InterruptThread it = new InterruptThread();
                  it.start();

                  InterruptThread2 it2 = new InterruptThread2();
                  it2.start();

                  InterruptThread3 it3 = new InterruptThread3();
                 
          // 此時it3阻塞在wait方法內
                  it3.start();
                 
          // 在外部調用iterrupt->it3收到InterruptedException->中斷狀態清除
                  it3.interrupt();

                 
          // true,因為這個是主線程調用的.所以此時it3還未被清除中斷狀態
                  LOGGER.debug("it3.isInterrupted:" + it3.isInterrupted());
                 
          // 做了一個等待.
                  Thread.sleep(3 * 1000);
                 
          // false,此時it3的中斷狀態已經被清楚
                  LOGGER.debug("it3.isInterrupted:" + it3.isInterrupted());
              }


             
          private static class InterruptThread extends Thread {
                  @Override
                 
          public void run() {
                     
          // false
                      LOGGER.debug("InterruptThread before interrupt.#interrupted:"
                             
          + interrupted());
                     
          // false
                      LOGGER.debug("InterruptThread before interrupt.#isInterrupted:"
                             
          + isInterrupted());

                     
          // 調用interrupt,這里直接設置了中斷狀態
                      LOGGER.debug("InterruptThread execute interrupt.");
                      interrupt();

                     
          // true
                     
          // 調用了#interrupt->#interrupted返回true->由下面的輸出可以看到,其清除了中斷狀態,所以下面的#isInterrupted返回了false
                      LOGGER.debug("InterruptThread after interrupt.#interrupted:"
                             
          + interrupted());
                     
          // false
                      LOGGER.debug("InterruptThread after interrupt.#isInterrupted:"
                             
          + isInterrupted());
                  }

              }


             
          private static class InterruptThread2 extends Thread {
                  @Override
                 
          public void run() {
                     
          // false
                      LOGGER.debug("InterruptThread2 before interrupt.#interrupted:"
                             
          + interrupted());
                     
          // false
                      LOGGER.debug("InterruptThread2 before interrupt.#isInterrupted:"
                             
          + isInterrupted());

                     
          // 調用interrupt
                      LOGGER.debug("InterruptThread2 execute interrupt.");
                      interrupt();

                     
          // true 這里#interrupt#->isInterrupted->返回true,即該方法不影響線程的中斷狀態
                      LOGGER.debug("InterruptThread2 after interrupt.#isInterrupted:"
                             
          + isInterrupted());

                     
          // true 這里#interrupted依然返回true并清除了中斷狀態.所以下面的輸出返回false
                      LOGGER.debug("InterruptThread2 after interrupt.#interrupted:"
                             
          + interrupted());

                     
          // false
                      LOGGER.debug("InterruptThread2.#isInterrupted:" + isInterrupted());

                     
          // false 這里再次調用#interrupted->返回了false.因為此時的狀態狀態已經為false了
                      LOGGER.debug("InterruptThread2.#interrupted:" + interrupted());

                  }

              }


             
          private static class InterruptThread3 extends Thread {
                 
          private final Object lock = new Object();

                  @Override
                 
          public void run() {
                     
          synchronized (lock) {
                         
          try {
                              lock.wait();
                          }
          catch (InterruptedException e) {
                              LOGGER.debug(
          "InterruptThread3#wait,is interrupted..");
                             
          // false
                              LOGGER.debug("InterruptThread3#wati,receive InterruptedException.#isInterrupted:"
                                     
          + isInterrupted());
                          }

                      }

                  }

              }

          }



          3.總結:通過代碼的方式簡單的總結了線程的interrupt,interrupted,isInterrupted三個方法.另外還提供了幾個正確結束線程的簡單方法demo.
          posted on 2013-12-06 17:11 landon 閱讀(2037) 評論(0)  編輯  收藏 所屬分類: Program
          主站蜘蛛池模板: 横山县| 读书| 常州市| 科技| 象山县| 临潭县| 达州市| 北流市| 都兰县| 鸡西市| 资源县| 洛浦县| 河西区| 闽清县| 四川省| 藁城市| 鄂托克前旗| 肇东市| 凤城市| 大同县| 永嘉县| 门头沟区| 广灵县| 桐梓县| 株洲市| 安庆市| 万全县| 昭苏县| 宁德市| 定襄县| 贺州市| 井陉县| 滕州市| 澜沧| 建德市| 和平县| 襄垣县| 蚌埠市| 遂川县| 桂东县| 错那县|