<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      多線程-interrupt(),isInterrupted(),interrupted()(轉(zhuǎn))

      Top

      背景

      • 由于使用stop方法停止線程非常暴力,可能會導致一系列問題。因此,提出一種溫和的方式:請求另外一個先不要在執(zhí)行了,這就是中斷方式。
      • 此外有這樣的場景:編寫 一個程序,需要暫停一段時間,于是調(diào)用Thread.sleep(),但是編譯器或IDE報錯說沒有處理檢查到的InterruptedException。對于InterruptedException,一種常見的處理方式是“生吞”它:捕獲它,然后什么也不做。
      • 在某個子線程中為了等待一些特定條件的到來, 你調(diào)用了Thread.sleep(10000), 預期線程睡10秒之后自己醒來, 但是如果這個特定條件提前到來的話, 來通知一個處于Sleep的線程。又比如說線程通過調(diào)用子線程的join方法阻塞自己以等待子線程結(jié)束, 但是子線程運行過程中發(fā)現(xiàn)自己沒辦法在短時間內(nèi)結(jié)束, 于是它需要想辦法告訴主線程別等我了。 這些情況下,,就需要中斷。
      • 在 java中啟動線程非常容易,大多數(shù)情況下我是讓一個線程執(zhí)行完自己的任務(wù)然后自己停掉,但是有時候我們需要取消某個操作,比如你在網(wǎng)絡(luò)下載時,有時候需要取消下載。實現(xiàn)線程的安全中斷并不是一件容易的事情,因為Java并不支持安全快速中斷線程的機制。

      中斷

      每個線程都有一個與之相關(guān)聯(lián)的 Boolean 屬性,用于表示線程的中斷狀態(tài)(interrupted status)中斷狀態(tài)初始時為 false;當另一個線程通過調(diào)用Thread.interrupt()中斷一個線程時,會出現(xiàn)以下兩種情況之一。(1)如果那個線程在執(zhí)行一個低級可中斷阻塞方法,例如Thread.sleep(), Thread.join()或 Object.wait(),那么它將取消阻塞并拋出InterruptedException。(2)否則,interrupt() 只是設(shè)置線程的中斷狀態(tài)。在被中斷線程中運行的代碼以后可以輪詢中斷狀態(tài),看看它是否被請求停止正在做的事情。中斷狀態(tài)可以通過 Thread.isInterrupted()來讀取,并且可以通過一個名為Thread.interrupted() 的操作讀取和清除。

      中斷是一種協(xié)作機制。當一個線程中斷另一個線程時,被中斷的線程不一定要立即停止正在做的事情。相反,中斷是禮貌地請求另一個線程在它愿意并且方便的時候停止它正在做的事情。有些方法,例如Thread.sleep(),很認真地對待這樣的請求,但每個方法不是一定要對中斷作出響應(yīng)。對于中斷請求,不阻塞但是仍然要花較長時間執(zhí)行的方法可以輪詢中斷狀態(tài),并在被中斷的時候提前返回。 您可以隨意忽略中斷請求,但是這樣做的話會影響響應(yīng)。

      中斷的協(xié)作特性所帶來的一個好處是,它為安全地構(gòu)造可取消活動提供更大的靈活性。我們很少希望一個活動立即停止;如果活動正在進行更新的時候被取消,那么程序數(shù)據(jù)結(jié)構(gòu)可能處于不一致狀態(tài)。中斷允許一個可取消活動來清理正在進行的工作,恢復不變量,通知其他活動它要被取消,然后才終止。

      相關(guān)方法

      this.interrupt()
      中斷調(diào)用該方法的線程,除非當前線程正在中斷自己,否則checkAccess方法有可能拋出SecurityException異常。
      (1)如果當前線程由于調(diào)用Object的wait(),或者Thread的join和sleep方法阻塞,則退出阻塞且中斷狀態(tài)將被清除,并且拋出InterrruptedException異常。

      (2)如果線程由于InterruptibleChannel的IO操作阻塞,則通道將關(guān)閉,線程設(shè)置中斷狀態(tài),并且線程收到一個ClosedInterruptException異常。

      (3)如果線程由于Selector阻塞,線程將處于中斷狀態(tài),并且從selection操作立刻返回,可能是一個非零值。
      除此之外,線程將被設(shè)置中斷狀態(tài)。

      總的來說:interrupt方法有兩個作用:(1)將線程的中斷狀態(tài)設(shè)置為true(2)讓被阻塞的線程拋出InterruptedException異常(同時中斷狀態(tài)為false)。

      這樣,對于那些阻塞方法(比如 wait() 和 sleep())而言,當另一個線程調(diào)用interrupt()中斷該線程時,該線程會從阻塞狀態(tài)退出并且拋出中斷異常。這樣,我們就可以捕捉到中斷異常,并根據(jù)實際情況對該線程從阻塞方法中異常退出而進行一些處理。

      注意:沒有占用CPU運行的線程是不可能給自己的中斷狀態(tài)置位的,就會產(chǎn)生一個InterruptedException異常。

      比如說:線程A獲得了鎖進入了同步代碼塊中,但由于條件不足調(diào)用 wait() 方法阻塞了。這個時候,線程B執(zhí)行 threadA.interrupt()請求中斷線程A,此時線程A就會拋出InterruptedException,我們就可以在catch中捕獲到這個異常并進行相應(yīng)處理(比如進一步往上拋出)

      this.isInterrupted()
      檢測調(diào)用該方法的線程是否被中斷,中斷狀態(tài)不會被清除。線程一旦被中斷,該方法返回true,而一旦sleep等方法拋出異常,它將清除中斷狀態(tài),此時方法將返回false

      package com.huawei.thread;
       
      public class Test30 {
       
          public static void main(String[] args) {
              Thread t = Thread.currentThread();
              System.out.println("1: " + t.isInterrupted());
              t.interrupt();
              System.out.println("2: " + t.isInterrupted());
              System.out.println("3: " + t.isInterrupted());
              try {
                  Thread.sleep(2000);
                  System.out.println("not interrted...");
              catch (Exception e) {
                  System.out.println("interrupted...");
                  System.out.println("4: " + t.isInterrupted());
              }
              System.out.println("5: " + t.isInterrupted());
          }
       
      }

       

      Thread.interrupted()
      檢測當前線程是否被中斷,并且中斷狀態(tài)會被清除(即重置為false);由于它是靜態(tài)方法,因此不能在特定的線程上使用,只能報告調(diào)用它的線程的中斷狀態(tài);如果該方法被調(diào)用兩次,則第二次一般是返回false,如果線程不存活,則返回false。

      package com.huawei.thread;
       
      public class Test31 {
          public static void main(String[] args) {
              System.out.println("1: " + Thread.interrupted());
              Thread.currentThread().interrupt();
              System.out.println("2: " + Thread.interrupted());
              System.out.println("3: " + Thread.interrupted());
          }
      }

       

      阻塞方法

      當一個方法拋出InterruptedException時,它不僅告訴你它可以拋出一個特定的檢查異常,而且還告訴你其他一些事情。例如,它告訴你它是一個阻塞blocking方法,如果你響應(yīng)得當?shù)脑挘鼘L試消除阻塞并盡早返回。

      阻塞方法不同于一般的要運行較長時間的方法。一般方法的完成只取決于它所要做的事情,以及是否有足夠多可用的計算資源(CPU 周期和內(nèi)存)。而阻塞方法的完成還取決于一些外部的事件,例如計時器到期,I/O 完成,或者另一個線程的動作(釋放一個鎖,設(shè)置一個標志,或者將一個任務(wù)放在一個工作隊列中)。一般方法在它們的工作做完后即可結(jié)束,而阻塞方法較難于預測,因為它們?nèi)Q于外部事件。阻塞方法可能影響響應(yīng)能力,因為難于預測它們何時會結(jié)束。

      阻塞方法可能因為等不到所等的事件而無法終止,因此令阻塞方法可取消就非常有用(如果長時間運行的非阻塞方法是可取消的,那么通常也非常有用)。可取消操作是指能從外部使之在正常完成之前終止的操作。由Thread提供并受Thread.sleep()和Object.wait()支持的中斷機制就是一種取消機制;它允許一個線程請求另一個線程停止它正在做的事情。當一個方法拋出InterruptedException時,它是在告訴你,如果執(zhí)行該方法的線程被中斷,它將嘗試停止它正在做的事情而提前返回,并通過拋出InterruptedException表明它提前返回。行為良好的阻塞庫方法應(yīng)該能對中斷作出響應(yīng)并拋出InterruptedException,以便能夠用于可取消活動中,而不至于影響響應(yīng)。

      不可中斷的阻塞方法

      并非所有的阻塞方法都拋出InterruptedException。輸入和輸出流類會阻塞等待 I/O 完成,但是它們不拋出InterruptedException,而且在被中斷的情況下也不會提前返回。然而,對于套接字 I/O,如果一個線程關(guān)閉套接字,則那個套接字上的阻塞 I/O 操作將提前結(jié)束,并拋出一個SocketException。java.nio中的非阻塞 I/O 類也不支持可中斷 I/O,但是同樣可以通過關(guān)閉通道或者請求Selector上的喚醒來取消阻塞操作。類似地,嘗試獲取一個內(nèi)部鎖的操作(進入一個synchronized 塊)是不能被中斷的,但是ReentrantLock支持可中斷的獲取模式。

      處理不支持中斷的線程中斷的常用方法

      如果一個線程由于同步記性IO操作導致阻塞,中斷請求不會拋出InterruptedException,該如何中斷此線程呢?

      package com.huawei.thread;
       
      import java.io.IOException;
      import java.io.InputStream;
      import java.net.Socket;
       
      public class Test32 extends Thread {
          public static final int BUF_SIZE = 512;
       
          Socket socket;
          InputStream in;
       
          public Test32(Socket socket) throws IOException {
              this.socket = socket;
              this.in = socket.getInputStream();
          }
       
          @Override
          public void interrupt() {
              try {
                  socket.close();
              catch (IOException e) {
       
              finally {
                  super.interrupt();
              }
          }
       
          @Override
          public void run() {
              try {
                  byte[] buf = new byte[BUF_SIZE];
                  while (true) {
                      int count = in.read(buf);
                      if (count < 0) {
                          break;
                      else if (count > 0) {
       
                      }
                  }
              catch (IOException e) {
       
              }
       
          }
       
      }

      通過改寫了Thread.interrupt方法,當調(diào)用interrupt方法時,會關(guān)閉socket,如果此時read方法阻塞,那么會拋出IOException異常,此時線程任務(wù)也就結(jié)束了。

      處理InterruptedException

      (1)如果拋出InterrruptedException意味著一個方法是阻塞方法,那么調(diào)用一個阻塞方法則意味著你的方法也是一個阻塞方法,應(yīng)該有某種策略來處理InterrruptedException。通常最容易的策略是自己拋出InterrruptedException,這樣做可以使方法對中斷做出響應(yīng),而且只需將InterruptedException添加到throws子句。

      public class TaskQueue {
          private static final int MAX_TASKS = 1000;
        
          private BlockingQueue<Task> queue = new LinkedBlockingQueue<Task>(MAX_TASKS);
        
          public void putTask(Task r) throws InterruptedException {
              queue.put(r);
          }
        
          public Task getTask() throws InterruptedException {
              return queue.take();
          }
      }

      (2)有時候需要在傳播異常之前進行一些清理工作,在這種情況下,可以捕獲InterruptedException,執(zhí)行清理,然后拋出異常。  

      public class PlayerMatcher {
          private PlayerSource players;
        
          public PlayerMatcher(PlayerSource players) {
              this.players = players;
          }
        
          public void matchPlayers() throws InterruptedException {
              try {
                   Player playerOne, playerTwo;
                   while (true) {
                       playerOne = playerTwo = null;
                       // Wait for two players to arrive and start a new game
                       playerOne = players.waitForPlayer(); // could throw IE
                       playerTwo = players.waitForPlayer(); // could throw IE
                       startNewGame(playerOne, playerTwo);
                   }
               }
               catch (InterruptedException e) { 
                   // If we got one player and were interrupted, put that player back
                   if (playerOne != null)
                       players.addFirst(playerOne);
                   // Then propagate the exception
                   throw e;
               }
          }
      }

      (3)不要生吞中斷:有時候拋出InterruptedException并不合適,例如當由Runnable定義的任務(wù)調(diào)用一個可中斷的方法時,在這種情況下,不能重新拋出InterruptedException,因為Runnable接口的run方法不允許拋出異常。當一個阻塞方法檢測到中斷并拋出InterruptedException但是不能重新拋出它,那么應(yīng)該保留中斷發(fā)生的證據(jù),以便調(diào)用棧中更高層的代碼能知道中斷,并對中斷做出響應(yīng),該任務(wù)可以通過調(diào)用interrupt()以重新中斷當前線程來完成。

      public class TaskRunner implements Runnable {
          private BlockingQueue<Task> queue;
        
          public TaskRunner(BlockingQueue<Task> queue) {
              this.queue = queue;
          }
        
          public void run() {
              try {
                   while (true) {
                       Task task = queue.take(10, TimeUnit.SECONDS);
                       task.execute();
                   }
               }
               catch (InterruptedException e) {
                   // Restore the interrupted status
                   Thread.currentThread().interrupt();
               }
          }
      } 

      待決中斷 

      sleep等方法的實現(xiàn)檢查到阻塞線程被中斷,它會友好的終止線程,并拋出InterruptedException異常。另外一種情況,如果線程在調(diào)用sleep等方法之前被中斷,那么該中斷就稱為:待決中斷,它會在剛調(diào)用sleep等方法時,立刻拋出InterruptedException異常。

      package com.huawei.thread;
       
      public class Test29 {
       
          public static void main(String[] args) {
              Thread.currentThread().interrupt();
              long start = System.currentTimeMillis();
              try {
                  Thread.sleep(40000);
                  System.out.println("not interrupted...");
              catch (Exception e) {
                  System.out.println("interrupted...");
              }
              System.out.println(System.currentTimeMillis() - start);
          }
      }

      運行結(jié)果如下:

      這種模式下,main線程中斷它自身。除了將中斷標志(它是Thread的內(nèi)部標志)設(shè)置為true外,沒有其他任何影響。線程被中斷了,但main線程仍然運行,main線程繼續(xù)監(jiān)視實時時鐘,并進入try塊,一旦調(diào)用sleep()方法,它就會注意到待決中斷的存在,并拋出InterruptException。于是執(zhí)行跳轉(zhuǎn)到catch塊,并打印出線程被中斷的信息。最后,計算并打印出時間差。

       實例1 

      public class Test27 {
       
          public static void main(String[] args) {
              try {
                  MyThread1 t = new MyThread1();
                  t.start();
                  Thread.sleep(2000);
                  t.interrupt(); // 中斷線程t
              catch (InterruptedException e) {
                  System.out.println("main catch");
                  e.printStackTrace();
              }
              System.out.println("end main");
          }
       
      }
       
      class MyThread1 extends Thread {
          @Override
          public void run() {
              for (int i = 1; i < 500000; i++) {
                  if (Thread.interrupted()) {
                      System.out.println("stop and exit...");
                      break;
                  }
                  System.out.println("i: " + i);
              }
                      // 盡管線程被中斷,但并沒有結(jié)束運行,這行代碼還是被執(zhí)行。
              System.out.println("end run...");
          }
      }

      運行結(jié)果部分截圖:

      當t獲取CPU執(zhí)行時,if判斷中,檢測到中斷狀態(tài),即在main線程中調(diào)用的t.interrupt(),for循環(huán)執(zhí)行break跳出for循環(huán),但是線程并沒有結(jié)束,還是繼續(xù)執(zhí)行for后面的語句。可以將break改成return,則線程立刻結(jié)束執(zhí)行。

      當然也可以拋出InterruptedException異常:

      class MyThread1 extends Thread {
          @Override
          public void run() {
              try {
                  for (int i = 1; i < 500000; i++) {
                      if (Thread.interrupted()) {
                          System.out.println("stop and exit...");
                          throw new InterruptedException();
                      }
                      System.out.println("i: " + i);
                  }
                  System.out.println("end run...");
              catch (Exception e) {
                  System.out.println("catch interrupted...");
              }
               
          }
      } 

      當檢測到中斷標識為true,拋出異常,這樣該線程就不會再執(zhí)行其他的正常語句。

      前面說過不能生吞中斷,修改如下:

      class MyThread1 extends Thread {
          @Override
          public void run() {
              try {
                  for (int i = 1; i < 500000; i++) {
                      if (Thread.interrupted()) {
                          System.out.println("stop and exit...");
                          throw new InterruptedException();
                      }
                      System.out.println("i: " + i);
                  }
                  System.out.println("end run...");
              catch (Exception e) {
                  System.out.println("catch interrupted...");
                  Thread.currentThread().interrupt(); // 不生吞中斷
              }
               
          }
      }  

      這樣,就由生吞異常,將異常進一步擴散了。

       實例2 

      package com.huawei.thread;
       
      public class Test28 extends Thread {
          volatile Boolean stop = false;
       
          public static void main(String[] args) throws InterruptedException {
              Test28 t = new Test28();
              System.out.println("starting thread...");
              t.start();
       
              Thread.sleep(3000);
       
              System.out.println("asking thread to stop...");
                      // 必須要在interrupt之前設(shè)置
              // 如果線程阻塞,將不會檢查此變量,調(diào)用interrupt之后,線程就可以盡早的終結(jié)被阻塞狀態(tài),能夠檢查這一變量
              t.stop = true;
                      // 如果線程沒有被阻塞,這時調(diào)用interrupt將不起作用。
              // 這一方法實際上完成的是:在線程受到阻塞時拋出一個中斷信號,這樣線程就可以退出阻塞狀態(tài)
              t.interrupt();
       
              Thread.sleep(3000);
              System.out.println("stopping app...");
          }
       
          @Override
          public void run() {
              while (!stop) {
                  System.out.println("running...");
                  try {
                      Thread.sleep(2000);
                  catch (InterruptedException e) {
                      System.out.println("interrupted...");
                  }
              }
              System.out.println("thread exit...");
          }
       
      } 

      把握幾個重點:stop變量、run方法中的sleep()、interrupt()、InterruptedException。串接起來就是這個意思:

      • 當我們在run方法中調(diào)用sleep(或其他阻塞線程的方法)時,如果線程阻塞的時間過長,比如10s,那在這10s內(nèi),線程阻塞,run方法不被執(zhí)行;
      • 但是如果在這10s內(nèi),stop被設(shè)置成true,表明要終止這個線程;但是,現(xiàn)在線程是阻塞的,它的run方法不能執(zhí)行,自然也就不能檢查stop,所以線程不能終止;
      • 這個時候,我們就可以用interrupt()方法了:我們在thread.stop = true;語句后調(diào)用thread.interrupt()方法, 該方法將在線程阻塞時拋出一個中斷信號,該信號將被catch語句捕獲到,一旦捕獲到這個信號,線程就提前終結(jié)自己的阻塞狀態(tài);
      • 這樣,它就能夠 再次運行run 方法了,然后檢查到stop = true,while循環(huán)就不會再被執(zhí)行,在執(zhí)行了while后面的清理工作之后,run方法執(zhí)行完 畢,線程終止。

      當代碼調(diào)用中需要拋出一個InterruptedException,可以選擇吧中斷狀態(tài)復位,也可以選在向外拋出InterruptedException,由外層的調(diào)用者來決定。

       參考資料

      http://www.rzrgm.cn/lujiango/p/7641983.html

       

      posted @ 2019-02-12 20:49  樓蘭胡楊  閱讀(401)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 久久精品久久电影免费理论片 | 国产亚洲欧洲av综合一区二区三区| 亚洲国产成人不卡高清麻豆| 又大又硬又爽免费视频| 色偷偷www.8888在线观看| 国产三级精品三级在线观看| 高清免费毛片| 97色成人综合网站| 女人喷液抽搐高潮视频| 称多县| 精品久久久久久无码免费| 熟女一区| 亚洲精品成a人在线观看| 九九热在线免费视频播放| 男人av无码天堂| 亚洲美免无码中文字幕在线| 无套内谢少妇一二三四| 国产精品不卡一二三区| 乱妇乱女熟妇熟女网站| 最新亚洲人成网站在线观看| 亚洲国产一区二区av| 精品国产成人A区在线观看| 人妻系列中文字幕精品| 国产精品一区二区小视频| 久久碰国产一区二区三区| 成人片黄网站色大片免费| 国产精品中文字幕日韩| 爆乳日韩尤物无码一区| 97无码人妻福利免费公开在线视频| 汕头市| 国产精品久久无中文字幕| 国内少妇偷人精品免费| 蜜桃视频无码区在线观看| 国产极品粉嫩尤物一区二区| 极品少妇无套内射视频| 永仁县| 亚洲国产亚洲综合在线尤物| 菠萝菠萝蜜午夜视频在线播放观看| 欧美一区二区三区久久综合| 国产一区二区三区小说| 国产成人a在线观看视频免费|