真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Java中怎么停止線程

今天就跟大家聊聊有關(guān)Java中怎么停止線程,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。

創(chuàng)新互聯(lián)-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設、高性價比根河網(wǎng)站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫,直接使用。一站式根河網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設找我們,業(yè)務覆蓋根河地區(qū)。費用合理售后完善,十年實體公司更值得信賴。

答題思路:

停止線程的正確方式是使用中斷  想停止線程需要停止方,被停止方,被停止方的子方法相互配合  擴展到常見的錯誤停止線程方法:已被廢棄的stop/suspend,無法喚醒阻塞線程的volatile

1. 正確方式是中斷

其實從邏輯上也很好理解的,一個線程正在運行,如何讓他停止?

A. 從外部直接調(diào)用該線程的stop方法,直接把線程停下來。

B. 從外部通過中斷通知線程停止,然后切換到被停止的線程,該線程執(zhí)行一系列邏輯后自己停止。

很明顯B方法要比A方法好很多,A方法太暴力了,你根本不知道被停止的線程在執(zhí)行什么任務就直接把他停止了,程序容易出問題;而B方法把線程停止交給線程本身去做,被停止的線程可以在自己的代碼中進行一些現(xiàn)場保護或者打印錯誤日志等方法再停止,更加合理,程序也更具健壯性。

下面要講的是線程如何能夠響應中斷,第一個方法是通過循環(huán)不斷判斷自身是否產(chǎn)生了中斷:

public class Demo1 implements Runnable{  @Override  public void run() {    int num = 0;    while(num <= Integer.MAX_VALUE / 2 && !Thread.currentThread().isInterrupted()){      if(num % 10000 == 0){        System.out.println(num);      }      num++;    }  }  public static void main(String[] args) throws InterruptedException {    Thread thread = new Thread(new Demo1());    thread.start();    thread.sleep(1000);    thread.interrupt();  }}

在上面的代碼中,我們在循環(huán)條件中不斷判斷線程本身是否產(chǎn)生了中斷,如果產(chǎn)生了中斷就不再打印

還有一個方法是通過java內(nèi)定的機制響應中斷:當線程調(diào)用sleep(),wait()方法后進入阻塞后,如果線程在阻塞的過程中被中斷了,那么線程會捕獲或拋出一個中斷異常,我們可以根據(jù)這個中斷異常去控制線程的停止。具體代碼如下:

public class Demo3 implements Runnable {  @Override  public void run() {    int num = 0;    try {      while(num < Integer.MAX_VALUE / 2){        if(num % 100 == 0){          System.out.println(num);        }        num++;        Thread.sleep(10);      }    } catch (InterruptedException e) {//捕獲中斷異常,在本代碼中,出現(xiàn)中斷異常后將退出循環(huán)      e.printStackTrace();    }  }  public static void main(String[] args) throws InterruptedException {    Thread thread = new Thread(new Demo3());    thread.start();    Thread.sleep(5000);    thread.interrupt();  }}

2. 各方配合才能完美停止

在上面的兩段代碼中已經(jīng)可以看到,想通過中斷停止線程是個需要多方配合。上面已經(jīng)演示了中斷方和被中斷方的配合,下面考慮更多的情況:假如要被停止的線程正在執(zhí)行某個子方法,這個時候該如何處理中斷?

有兩個辦法:第一個是把中斷傳遞給父方法,第二個是重新設置當前線程為中斷。

先說第一個例子:在子方法中把中斷異常上拋給父方法,然后在父方法中處理中斷:

public class Demo4 implements Runnable{  @Override  public void run() {    try{//在父方法中捕獲中斷異常      while(true){        System.out.println("go");        throwInterrupt();      }    }catch (InterruptedException e) {      e.printStackTrace();      System.out.println("檢測到中斷,保存錯誤日志");    }  }  private void throwInterrupt() throws InterruptedException {//把中斷上傳給父方法    Thread.sleep(2000);  }  public static void main(String[] args) throws InterruptedException {    Thread thread = new Thread(new Demo4());    thread.start();    Thread.sleep(1000);    thread.interrupt();  }}

第二個例子:在子方法中捕獲中斷異常,但是捕獲以后當前線程的中斷控制位將被清除,父方法執(zhí)行時將無法感知中斷。所以此時在子方法中重新設置中斷,這樣父方法就可以通過對中斷控制位的判斷來處理中斷:

public class Demo5 implements Runnable{  @Override  public void run() {    while(true && !Thread.currentThread().isInterrupted()){//每次循環(huán)判斷中斷控制位      System.out.println("go");      throwInterrupt();    }    System.out.println("檢測到了中斷,循環(huán)打印退出");  }  private void throwInterrupt(){    try {      Thread.sleep(2000);    } catch (InterruptedException e) {      Thread.currentThread().interrupt();//重新設置中斷      e.printStackTrace();    }  }  public static void main(String[] args) throws InterruptedException {    Thread thread = new Thread(new Demo5());    thread.start();    Thread.sleep(1000);    thread.interrupt();  }}

講到這里,正確的停止線程方法已經(jīng)講的差不多了,下面我們看一下常見的錯誤停止線程的例子:

3. 常見錯誤停止線程例子:

這里介紹兩種常見的錯誤,先說比較好理解的一種,也就是開頭所說的,在外部直接把運行中的線程停止掉。這種暴力的方法很有可能造成臟數(shù)據(jù)。

看下面的例子:

public class Demo6 implements Runnable{  /**   * 模擬指揮軍隊,以一個連隊為單位領取武器,一共有5個連隊,一個連隊10個人   */  @Override  public void run() {    for(int i = 0; i < 5; i++){      System.out.println("第" + (i + 1) + "個連隊開始領取武器");      for(int j = 0; j < 10; j++){        System.out.println("第" + (j + 1) + "個士兵領取武器");        try {          Thread.sleep(100);        } catch (InterruptedException e) {          e.printStackTrace();        }      }      System.out.println("第" + (i + 1) + "個連隊領取武器完畢");    }  }  public static void main(String[] args) throws InterruptedException {    Thread thread = new Thread(new Demo6());    thread.start();    Thread.sleep(2500);    thread.stop();  }}

在上面的例子中,我們模擬軍隊發(fā)放武器,規(guī)定一個連為一個單位,每個連有10個人。當我們直接從外部通過stop方法停止武器發(fā)放后。很有可能某個連隊正處于發(fā)放武器的過程中,導致部分士兵沒有領到武器。

這就好比在生產(chǎn)環(huán)境中,銀行以10筆轉(zhuǎn)賬為一個單位進行轉(zhuǎn)賬,如果線程在轉(zhuǎn)賬的中途被突然停止,那么很可能會造成臟數(shù)據(jù)。

另外一個“常見”錯誤可能知名度不是太高,就是:通過volatile關(guān)鍵字停止線程。具體來說就是通過volatile關(guān)鍵字定義一個變量,通過判斷變量來停止線程。這個方法表面上是沒問題的,我們先看這個表面的例子:

public class Demo7 implements Runnable {  private static volatile boolean canceled = false;  @Override  public void run() {    int num = 0;    while(num <= Integer.MAX_VALUE / 2 && !canceled){      if(num % 100 == 0){        System.out.println(num + "是100的倍數(shù)");      }      num++;    }    System.out.println("退出");  }  public static void main(String[] args) throws InterruptedException {    Thread thread = new Thread(new Demo7());    thread.start();    Thread.sleep(1000);    canceled = true;  }}

但是這個方法有一個潛在的大漏洞,就是若線程進入了阻塞狀態(tài),我們將不能通過修改volatile變量來停止線程,看下面的生產(chǎn)者消費者例子:

/** * 通過生產(chǎn)者消費者模式演示volatile的局限性,volatile不能喚醒已經(jīng)阻塞的線程 * 生產(chǎn)者生產(chǎn)速度很快,消費者消費速度很慢,通過阻塞隊列存儲商品 */public class Demo8 {  public static void main(String[] args) throws InterruptedException {    ArrayBlockingQueue storage = new ArrayBlockingQueue(10);    Producer producer = new Producer(storage);    Thread producerThread = new Thread(producer);    producerThread.start();    Thread.sleep(1000);//1s足夠讓生產(chǎn)者把阻塞隊列塞滿    Consumer consumer = new Consumer(storage);    while(consumer.needMoreNums()){      System.out.println(storage.take() + "被消費");      Thread.sleep(100);//讓消費者消費慢一點,給生產(chǎn)者生產(chǎn)的時間    }    System.out.println("消費者消費完畢");    producer.canceled = true;//讓生產(chǎn)者停止生產(chǎn)(實際情況是不行的,因為此時生產(chǎn)者處于阻塞狀態(tài),volatile不能喚醒阻塞狀態(tài)的線程)  }}class Producer implements Runnable{  public volatile boolean canceled = false;  private BlockingQueue storage;  public Producer(BlockingQueue storage) {    this.storage = storage;  }  @Override  public void run() {    int num = 0;    try{      while(num < Integer.MAX_VALUE / 2 && !canceled){        if(num % 100 == 0){          this.storage.put(num);          System.out.println(num + "是100的倍數(shù),已經(jīng)被放入倉庫");        }        num++;      }    } catch (InterruptedException e) {      e.printStackTrace();    }finally {      System.out.println("生產(chǎn)者停止生產(chǎn)");    }  }}class Consumer{  private BlockingQueue storage;  public Consumer(BlockingQueue storage) {    this.storage = storage;  }  public boolean needMoreNums(){    return Math.random() < 0.95 ? true : false;  }}

上面的例子運行后會發(fā)現(xiàn)生產(chǎn)線程一直不能停止,因為他處于阻塞狀態(tài),當消費者線程退出后,沒有任何東西能喚醒生產(chǎn)者線程。

這種錯誤用中斷就很好解決:

/** * 通過生產(chǎn)者消費者模式演示volatile的局限性,volatile不能喚醒已經(jīng)阻塞的線程 * 生產(chǎn)者生產(chǎn)速度很快,消費者消費速度很慢,通過阻塞隊列存儲商品 */public class Demo8 {  public static void main(String[] args) throws InterruptedException {    ArrayBlockingQueue storage = new ArrayBlockingQueue(10);    Producer producer = new Producer(storage);    Thread producerThread = new Thread(producer);    producerThread.start();    Thread.sleep(1000);//1s足夠讓生產(chǎn)者把阻塞隊列塞滿    Consumer consumer = new Consumer(storage);    while(consumer.needMoreNums()){      System.out.println(storage.take() + "被消費");      Thread.sleep(100);//讓消費者消費慢一點,給生產(chǎn)者生產(chǎn)的時間    }    System.out.println("消費者消費完畢");    producerThread.interrupt();  }}class Producer implements Runnable{  private BlockingQueue storage;  public Producer(BlockingQueue storage) {    this.storage = storage;  }  @Override  public void run() {    int num = 0;    try{      while(num < Integer.MAX_VALUE / 2 && !Thread.currentThread().isInterrupted()){        if(num % 100 == 0){          this.storage.put(num);          System.out.println(num + "是100的倍數(shù),已經(jīng)被放入倉庫");        }        num++;      }    } catch (InterruptedException e) {      e.printStackTrace();    }finally {      System.out.println("生產(chǎn)者停止生產(chǎn)");    }  }}class Consumer{  private BlockingQueue storage;  public Consumer(BlockingQueue storage) {    this.storage = storage;  }  public boolean needMoreNums(){    return Math.random() < 0.95 ? true : false;  }}

4. 擴展

可能你還會問:如何處理不可中斷的阻塞?

只能說很遺憾沒有一個通用的解決辦法,我們需要針對特定的鎖或io給出特定的解決方案。對于這些特殊的例子,api一般會給出可以響應中斷的操作方法,我們要選用那些特定的方法,沒有萬能藥。

看完上述內(nèi)容,你們對Java中怎么停止線程有進一步的了解嗎?如果還想了解更多知識或者相關(guān)內(nèi)容,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝大家的支持。


本文標題:Java中怎么停止線程
文章源于:http://weahome.cn/article/jgcgsp.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部