成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

深入分析Java線程中斷機(jī)制

開發(fā) 后端
在平時(shí)的開發(fā)過程中,相信都會(huì)使用到多線程,在使用多線程時(shí),大家也會(huì)遇到各種各樣的問題,今天我們就來說說一個(gè)多線程的問題——線程中斷。在 java中啟動(dòng)線程非常容易,大多數(shù)情況下我是讓一個(gè)線程執(zhí)行完自己的任務(wù)然后自己停掉,但是有時(shí)候我們需要取消某個(gè)操作,比如你在網(wǎng)絡(luò)下載時(shí),有時(shí)候需 要取消下載。

Thread.interrupt真的能中斷線程嗎

在平時(shí)的開發(fā)過程中,相信都會(huì)使用到多線程,在使用多線程時(shí),大家也會(huì)遇到各種各樣的問題,今天我們就來說說一個(gè)多線程的問題——線程中斷。在 java中啟動(dòng)線程非常容易,大多數(shù)情況下我是讓一個(gè)線程執(zhí)行完自己的任務(wù)然后自己停掉,但是有時(shí)候我們需要取消某個(gè)操作,比如你在網(wǎng)絡(luò)下載時(shí),有時(shí)候需 要取消下載。實(shí)現(xiàn)線程的安全中斷并不是一件容易的事情,因?yàn)镴ava并不支持安全快速中斷線程的機(jī)制,這里估計(jì)很多同學(xué)就會(huì)說了,java不是提供了Thread.interrupt 方法中斷線程嗎,好吧,我們今天就從這個(gè)方法開始說起。

深入分析Java線程中斷機(jī)制

但是調(diào)用此方法線程真的會(huì)停止嗎?我們寫個(gè)demo看看就知道了。

 

  1. public class Main { 
  2.   private static final String TAG = "Main"
  3.   public static void main(String[] args) { 
  4.     Thread t=new Thread(new NRunnable()); 
  5.     t.start(); 
  6.     System.out.println("is start......."); 
  7.     try { 
  8.       Thread.sleep(3000); 
  9.     } catch (InterruptedException e) { 
  10.  
  11.     } 
  12.  
  13.     t.interrupt(); 
  14.     System.out.println("is interrupt......."); 
  15.  
  16.   } 
  17.  
  18.   public static class NRunnable implements Runnable 
  19.   { 
  20.  
  21.     @Override 
  22.     public void run() { 
  23.       while(true
  24.       { 
  25.         System.out.println("我沒有種中斷"); 
  26.         try { 
  27.           Thread.sleep(1000); 
  28.         } catch (InterruptedException e) { 
  29.  
  30.         } 
  31.       } 
  32.     } 
  33.  
  34.   } 

如果interrutp方法能夠中斷線程,那么在打印了is interrupt…….之后應(yīng)該是沒有l(wèi)og了,我們看看執(zhí)行結(jié)果吧

is start.......
我沒有種中斷
我沒有種中斷
我沒有種中斷
我沒有種中斷
我沒有種中斷
is interrupt.......
我沒有種中斷
我沒有種中斷
我沒有種中斷
我沒有種中斷
我沒有種中斷
....

通過結(jié)果可以發(fā)現(xiàn)子線程并沒有中斷

所以 Thread.interrupt() 方法并不能中斷線程,該方法僅僅告訴線程外部已經(jīng)有中斷請(qǐng)求,至于是否中斷還取決于線程自己。在Thread類中除了interrupt() 方法還有另外兩個(gè)非常相似的方法:interrupted 和 isInterrupted 方法,下面來對(duì)這幾個(gè)方法進(jìn)行說明:

  • interrupt 此方法是實(shí)例方法,用于告訴此線程外部有中斷請(qǐng)求,并且將線程中的中斷標(biāo)記設(shè)置為true

  • interrupted 此方法是類方法,測(cè)試當(dāng)前線程是否已經(jīng)中斷。線程的中斷狀態(tài) 由該方法清除。換句話說,如果連續(xù)兩次調(diào)用該方法,則第二次調(diào)用將返回 false(在***次調(diào)用已清除了其中斷狀態(tài)之后,且第二次調(diào)用檢驗(yàn)完中斷狀態(tài)前,當(dāng)前線程再次中斷的情況除外)。

  • isInterrupted 此方法是實(shí)例方法測(cè)試線程是否已經(jīng)中斷。線程的中斷狀態(tài) 不受該方法的影響。 線程中斷被忽略,因?yàn)樵谥袛鄷r(shí)不處于活動(dòng)狀態(tài)的線程將由此返回 false 的方法反映出來

處理線程中斷的常用方法

設(shè)置取消標(biāo)記

還是用上面的例子,只不過做了些修改

 

  1. public static void main(String[] args) { 
  2.     NRunnable run=new NRunnable(); 
  3.     Thread t=new Thread(run); 
  4.     t.start(); 
  5.     System.out.println("is start......."); 
  6.     try { 
  7.       Thread.sleep(3000); 
  8.     } catch (InterruptedException e) { 
  9.  
  10.     } 
  11.     run.cancel(); 
  12.     System.out.println("cancel ..."+System.currentTimeMillis()); 
  13.   } 
  14.  
  15.   public static class NRunnable implements Runnable 
  16.   { 
  17.     public boolean isCancel=false
  18.  
  19.     @Override 
  20.     public void run() { 
  21.       while(!isCancel) 
  22.       { 
  23.         System.out.println("我沒有種中斷"); 
  24.         try { 
  25.           Thread.sleep(10000); 
  26.         } catch (InterruptedException e) { 
  27.  
  28.         } 
  29.       } 
  30.       System.out.println("我已經(jīng)結(jié)束了..."+System.currentTimeMillis()); 
  31.     } 
  32.  
  33.     public void cancel() 
  34.     { 
  35.       this.isCancel=true
  36.     } 
  37.  
  38.   } 

執(zhí)行結(jié)果如下:

is start.......
我沒有種中斷
cancel ...1438396915809
我已經(jīng)結(jié)束了...1438396922809

通過結(jié)果,我們發(fā)現(xiàn)線程確實(shí)已經(jīng)中斷了,但是細(xì)心的同學(xué)應(yīng)該發(fā)現(xiàn)了一個(gè)問題,調(diào)用cancel方法和***線程執(zhí)行完畢之間隔了好幾秒的時(shí)間,也就是說線程不是立馬中斷的,我們下面來分析一下原因:

子線程退出的條件是while循環(huán)結(jié)束,也就是cancel標(biāo)示設(shè)置為true,但是當(dāng)我們調(diào)用cancel方法將calcel標(biāo)記設(shè)置為true 時(shí),while循環(huán)里面有一個(gè)耗時(shí)操作(sleep方法模擬),只有等待耗時(shí)操作執(zhí)行完畢后才會(huì)去檢查這個(gè)標(biāo)記,所以cancel方法和線程退出中間有時(shí) 間間隔。

通過interrupt 和 isinterrupt 方法來中斷線程

 

  1. public static void main(String[] args) { 
  2.     Thread t=new NThread(); 
  3.     t.start(); 
  4.     System.out.println("is start......."); 
  5.     try { 
  6.       Thread.sleep(3000); 
  7.     } catch (InterruptedException e) { 
  8.  
  9.     } 
  10.     System.out.println("start interrupt..."+System.currentTimeMillis()); 
  11.     t.interrupt(); 
  12.     System.out.println("end interrupt ..."+System.currentTimeMillis()); 
  13.   } 
  14.  
  15.   public static class NThread extends Thread 
  16.   { 
  17.  
  18.     @Override 
  19.     public void run() { 
  20.       while(!this.isInterrupted()) 
  21.       { 
  22.         System.out.println("我沒有種中斷"); 
  23.         try { 
  24.           Thread.sleep(10000); 
  25.         } catch (InterruptedException e) { 
  26.           Thread.currentThread().interrupt(); 
  27.         } 
  28.       } 
  29.       System.out.println("我已經(jīng)結(jié)束了..."+System.currentTimeMillis()); 
  30.     } 
  31.  
  32.   } 

運(yùn)行結(jié)果如下:

is start.......
我沒有種中斷
start interrupt...1438398800110
我已經(jīng)結(jié)束了...1438398800110
end interrupt ...1438398800110

這次是立馬中斷的,但是這種方法是由局限性的,這種方法僅僅對(duì)于會(huì)拋出InterruptedException 異常的任務(wù)時(shí)有效的,比如java中的sleep、wait 等方法,對(duì)于不會(huì)拋出這種異常的任務(wù)其效果其實(shí)和***種方法是一樣的,都會(huì)有延遲性,這個(gè)例子中還有一個(gè)非常重要的地方就是cache語句中,我們調(diào)用了Thread.currentThread().interrupt() 我們把這句代碼去掉,運(yùn)行你會(huì)發(fā)現(xiàn)這個(gè)線程無法終止,因?yàn)樵趻伋?code>InterruptedException 的同時(shí),線程的中斷標(biāo)志被清除了,所以在while語句中判斷當(dāng)前線程是否中斷時(shí),返回的是false.針對(duì)InterruptedException 異常,我想說的是:一定不能再catch語句塊中什么也不干,如果你實(shí)在不想處理,你可以將異常拋出來,讓調(diào)用拋異常的方法也成為一個(gè)可以拋出InterruptedException 的方法,如果自己要捕獲此異常,那么***在cache語句中調(diào)用 Thread.currentThread().interrupt(); 方法來讓高層只要中斷請(qǐng)求并處理該中斷。

對(duì)于上述兩種方法都有其局限性,***種方法只能處理那種工作量不大,會(huì)頻繁檢查循環(huán)標(biāo)志的任務(wù),對(duì)于第二種方法適合用于拋出InterruptedException的代碼。也就是說***種和第二種方法支持的是支持中斷的線程任務(wù),那么不支持中斷的線程任務(wù)該怎么做呢。

例如 如果一個(gè)線程由于同步進(jìn)行I/O操作導(dǎo)致阻塞,中斷請(qǐng)求不會(huì)拋出InterruptedException ,我們?cè)撊绾沃袛啻司€程呢。

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

改寫線程的interrupt方法

 

  1. public static class ReaderThread extends Thread 
  2.    public static final int BUFFER_SIZE=512
  3.    Socket socket; 
  4.    InputStream is; 
  5.  
  6.    public ReaderThread(Socket socket) throws IOException 
  7.    { 
  8.      this.socket=socket; 
  9.      is=this.socket.getInputStream(); 
  10.    } 
  11.  
  12.    @Override 
  13.   public void interrupt() { 
  14.      try 
  15.      { 
  16.        socket.close(); 
  17.      }catch(IOException e) 
  18.      { 
  19.  
  20.      }finally 
  21.      { 
  22.        super.interrupt(); 
  23.      } 
  24.     super.interrupt(); 
  25.   } 
  26.    @Override 
  27.   public void run() { 
  28.      try 
  29.      { 
  30.        byte[]buf=new byte[BUFFER_SIZE]; 
  31.        while(true
  32.        { 
  33.          int count=is.read(buf); 
  34.          if(count<0
  35.            break
  36.          else if(count>0
  37.          { 
  38.  
  39.          } 
  40.        } 
  41.      }catch(IOException e) 
  42.      { 
  43.  
  44.      } 
  45.   } 

例如在上面的例子中,改寫了Thread的interrupt 方法,當(dāng)調(diào)用interrupt 方法時(shí),會(huì)關(guān)閉socket,如果此時(shí)read方法阻塞,那么會(huì)拋出IOException 此時(shí)線程任務(wù)也就結(jié)束了。

以上方法是通過改寫線程的interrupt 方法實(shí)現(xiàn),那么對(duì)于使用線程池的任務(wù)該怎么中斷呢。

改寫線程池的newTaskFor方法

通常我們向線程池中加入一個(gè)任務(wù)采用如下形式:

 

  1. Future<?> future=executor.submit(new Runnable(){ 
  2.       @Override 
  3.       public void run() { 
  4.  
  5.       } 
  6.     }); 
  7.  
  8. 取消任務(wù)時(shí),調(diào)用的是future的cancel方法,其實(shí)在cancel方法中調(diào)用的是線程的interrupt方法。所以對(duì)于不支持中斷的任務(wù)cancel也是無效的,下面我們看看submit方法里面干了上面吧 
  9.  
  10.     public Future<?> submit(Runnable task) { 
  11.         if (task == nullthrow new NullPointerException(); 
  12.         RunnableFuture<Void> ftask = newTaskFor(task, null); 
  13.         execute(ftask); 
  14.         return ftask; 
  15.     } 
  16.  
  17. 這里調(diào)用的是AbstractExecutorService 的newTaskFor方法,那么我們能不能改寫ThreadPoolExecutor的newTaskFor方法呢,接下來看我在處理吧 
  18.  
  19. 定義一個(gè)基類,所有需要取消的任務(wù)繼承這個(gè)基類 
  20.  
  21. public interface CancelableRunnable<T> extends Runnable { 
  22.  
  23.   public void cancel(); 
  24.   public RunnableFuture<T> newTask(); 
  25.  
  26.  
  27. 將上面的ReaderThread改為繼承這個(gè)類 
  28.  
  29.  public static class ReaderThread implements CancelableRunnable<Void> 
  30.   { 
  31.     public static final int BUFFER_SIZE=512
  32.     Socket socket; 
  33.     InputStream is; 
  34.  
  35.     public ReaderThread(Socket socket) throws IOException 
  36.     { 
  37.       this.socket=socket; 
  38.       is=this.socket.getInputStream(); 
  39.     } 
  40.  
  41.     @Override 
  42.    public void run() { 
  43.       try 
  44.       { 
  45.         byte[]buf=new byte[BUFFER_SIZE]; 
  46.         while(true
  47.         { 
  48.           int count=is.read(buf); 
  49.           if(count<0
  50.             break
  51.           else if(count>0
  52.           { 
  53.  
  54.           } 
  55.         } 
  56.       }catch(IOException e) 
  57.       { 
  58.  
  59.       } 
  60.    } 
  61.  
  62.     @Override 
  63.     public void cancel() { 
  64.       try { 
  65.         socket.close(); 
  66.       } catch (IOException e) { 
  67.  
  68.       } 
  69.     } 
  70.  
  71.     @Override 
  72.     public RunnableFuture<Void> newTask() { 
  73.       return new FutureTask<Void>(this,null
  74.           { 
  75.             @Override 
  76.             public boolean cancel(boolean mayInterruptIfRunning) { 
  77.               return super.cancel(mayInterruptIfRunning); 
  78.               if(ReaderThread.this instanceof CancelableRunnable)) 
  79.               { 
  80.                 ((CancelableRunnable)(ReaderThread.this)).cancel(); 
  81.               }else 
  82.               { 
  83.                 super.cancel(mayInterruptIfRunning); 
  84.               } 
  85.             } 
  86.           }; 
  87.  
  88.     } 

當(dāng)你調(diào)用future的cancel的方法時(shí),它會(huì)關(guān)閉socket,最終導(dǎo)致read方法異常,從而終止線程任務(wù)。

責(zé)任編輯:王雪燕 來源: yuanzeyao
相關(guān)推薦

2010-09-07 14:21:22

PPPoE協(xié)議

2022-04-12 08:30:45

TomcatWeb 應(yīng)用Servlet

2011-03-23 11:01:55

LAMP 架構(gòu)

2020-12-07 06:23:48

Java內(nèi)存

2023-02-01 08:13:30

Redis內(nèi)存碎片

2011-09-01 13:51:52

JavaScript

2010-03-08 14:53:48

Linux分區(qū)

2009-12-16 16:39:01

Visual Stud

2009-06-10 18:12:38

Equinox動(dòng)態(tài)化OSGi動(dòng)態(tài)化

2022-08-30 07:00:18

執(zhí)行引擎Hotspot虛擬機(jī)

2009-12-14 14:50:46

Ruby傳參數(shù)

2021-10-29 16:36:53

AMSAndroidActivityMan

2018-10-25 15:24:10

ThreadLocal內(nèi)存泄漏Java

2018-12-18 10:11:37

軟件復(fù)雜度軟件系統(tǒng)軟件開發(fā)

2021-04-13 12:55:06

SpringMVC解析器接口

2023-08-07 07:44:44

2011-09-13 09:08:22

架構(gòu)

2013-11-14 17:02:41

Android多窗口

2009-07-03 11:14:57

2011-06-28 14:11:33

JavaScript
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 毛片免费观看视频 | 亚洲欧美一区二区三区国产精品 | 日本 欧美 三级 高清 视频 | 亚洲视频精品 | 国产精品区一区二区三区 | 亚洲成人一区二区 | 午夜国产一级片 | 日韩精品免费在线 | 亚洲成a人片 | 日本二区 | 日本午夜网站 | 欧美一级欧美三级在线观看 | 久久久久午夜 | 欧美一区二区成人 | 精品一区二区三区日本 | 成人黄色电影免费 | 久久成人一区 | 欧美日韩亚洲国产 | 久草高清视频 | 精品国产免费一区二区三区五区 | 日本超碰在线 | 久久爱黑人激情av摘花 | 在线免费观看日本 | 亚洲欧美成人在线 | 国产精品一区二区av | 亚洲欧美在线一区 | 国产精品一区二区无线 | 国产一区二区三区四区五区3d | 五月婷婷丁香 | 青青草视频网站 | 亚洲欧美日韩精品久久亚洲区 | 中文字幕亚洲国产 | 亚洲va中文字幕 | 成人免费在线观看 | 爱高潮www亚洲精品 中文字幕免费视频 | 久久免费香蕉视频 | 一区二区在线 | 91av在线影院 | 欧美成人猛片aaaaaaa | 久久99精品国产99久久6男男 | 欧美国产精品一区二区 |