隨筆-204  評(píng)論-149  文章-0  trackbacks-0
          在學(xué)校的論壇Java版發(fā)現(xiàn)很多問關(guān)于這樣的問題,比如這幾個(gè)方法有什么區(qū)別,想看t.interrupt()方法后線程的中斷狀態(tài);如何終止一個(gè)線程
          其實(shí)之前已經(jīng)大部分提及到。現(xiàn)總結(jié)一下,然后加上例子,畢竟例子容易理解
          http://www.aygfsteel.com/fhtdy2004/archive/2009/06/08/280728.html中有關(guān)interrupt()的解釋已經(jīng)很清楚了

          interrupt

          public void interrupt()
          中斷線程。

          如果當(dāng)前線程沒有中斷它自己(這在任何情況下都是允許的),則該線程的 checkAccess 方法就會(huì)被調(diào)用,這可能拋出 SecurityException

          如果線程在調(diào)用 Object 類的 wait()wait(long)wait(long, int) 方法,或者該類的 join()join(long)join(long, int)sleep(long)sleep(long, int) 方法過程中受阻,則其中斷狀態(tài)將被清除,它還將收到一個(gè) InterruptedException

          如果該線程在可中斷的通道上的 I/O 操作中受阻,則該通道將被關(guān)閉,該線程的中斷狀態(tài)將被設(shè)置并且該線程將收到一個(gè) ClosedByInterruptException

          如果該線程在一個(gè) Selector 中受阻,則該線程的中斷狀態(tài)將被設(shè)置,它將立即從選擇操作返回,并可能帶有一個(gè)非零值,就好像調(diào)用了選擇器的 wakeup 方法一樣。

          如果以前的條件都沒有保存,則該線程的中斷狀態(tài)將被設(shè)置。

           

          拋出:
          SecurityException - 如果當(dāng)前線程無法修改該線程

          interrupted

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

           

          返回:
          如果當(dāng)前線程已經(jīng)中斷,則返回 true;否則返回 false
          另請(qǐng)參見:
          isInterrupted()

          isInterrupted

          public boolean isInterrupted()
          測試線程是否已經(jīng)中斷。線程的中斷狀態(tài) 不受該方法的影響。

           

          返回:
          如果該線程已經(jīng)中斷,則返回 true;否則返回 false
          另請(qǐng)參見:
          interrupted()

          t.interrupt()不會(huì)中斷正在執(zhí)行的線程,只是將線程的標(biāo)志位設(shè)置成true。但是如果線程在調(diào)用sleep(),join(),wait()方法時(shí)線程被中斷,則這些方法會(huì)拋出InterruptedException,在catch塊中捕獲到這個(gè)異常時(shí),線程的中斷標(biāo)志位已經(jīng)被設(shè)置成false了,因此在此catch塊中調(diào)用t.isInterrupted(),Thread.interrupted()始終都為false,
          而t.isInterrupted與Thread.interrupted()的區(qū)別是API中已經(jīng)說明很明顯了,Thread.interrupted()假如當(dāng)前的中斷標(biāo)志為true,則調(diào)完后會(huì)將中斷標(biāo)志位設(shè)置成false
          package threadtest;

          import java.util.Timer;
          import java.util.TimerTask;

          class CanStop extends Thread {

              
          private int counter = 0;

              
          public void run() {
                  
          boolean done = false;
                  
          try{
                      Thread.sleep(
          100);//設(shè)置成100比主線程中的500要小
                  }
          catch(InterruptedException ie){
                      ie.printStackTrace();
                      
          //return;假如要使用interrupt來終止線程則在捕獲的InterruptedException中return
                  }

                  
          while (counter < 100000 &&!done) {
                      System.out.println(counter
          ++);
                      
          //在主線程中調(diào)用stoppable.interrupt()之前為false,假如之后沒有調(diào)用Thread.interrupted()則一直為true,
                      
          //否則為第一次為true,調(diào)用Thread.interrupted之后為false
                      System.out.println("in thread stoppable.isInterrupted() "+isInterrupted());
                      
                      
          //System.out.println("stoppable.isInterrupted() "+Thread.interrupted());////在主線程中調(diào)用stoppable.interrupt()之前為false,之后只有第一個(gè)會(huì)顯示為true,之后全為false
                      
                      
          //調(diào)用Thread.interrupted()一次會(huì)清除線程的中斷標(biāo)志位,因此以后都為false
                      if(Thread.interrupted()==true){
                          
          try{
                              
          //Thread.interrupted()會(huì)清除中斷標(biāo)志位,顯然這里面只會(huì)調(diào)用一次
                              System.out.println("in thread after Thread.interrupted() "+isInterrupted());
                              sleep(
          10000);
                          }
          catch(InterruptedException ie){
                              ie.printStackTrace();
                              
                          }

                      }

                  }

              }

              
          }


          public class CheckInterrupt {
              
          public static void main(String[] args) {
                  
          final CanStop stoppable = new CanStop();
                  stoppable.start();
                  
          new Timer(true).schedule(new TimerTask() {
                      
          public void run() {
                          System.out.println(
          "Requesting Interrupt");
                          stoppable.interrupt();
          //不會(huì)中斷正在執(zhí)行的線程,原因是因?yàn)閕nterrupt()方法只設(shè)置中斷狀態(tài)標(biāo)志位為true
                          System.out.println("in timer stoppable.isInterrupted() "+stoppable.isInterrupted());
                      }

                  }
          500); // run() after 500 milliseconds
              }

          }



          2,關(guān)于interrupte()打斷sleep()
          package threadtest;

          //Understanding join().

          class Sleeper extends Thread {
              
          private int duration;

              
          public Sleeper(String name, int sleepTime) {
                  
          super(name);
                  duration 
          = sleepTime;
                  start();
              }


              
          public void run() {
                  
          try {
                      sleep(duration);
                  }
           catch (InterruptedException e) {
                      
          // System.out.println(getName() + " was interrupted. " +
                      
          // "isInterrupted(): " + isInterrupted());
                      System.out.println(getName() + " in catch Thread.interrupted(). "
                              
          + "Thread.interrupted(): " + Thread.interrupted());
                      
          return;
                  }

                  System.out.println(getName() 
          + " has awakened");
              }

          }


          class Joiner extends Thread {
              
          private Sleeper sleeper;

              
          public Joiner(String name, Sleeper sleeper) {
                  
          super(name);
                  
          this.sleeper = sleeper;
                  start();
              }


              
          public void run() {
                  
          try {
                      sleeper.join();
                  }
           catch (InterruptedException e) {
                      
          //run方法不能Throw CheckedException,要拋只能拋出RuntimeException,也不會(huì)被主線程捕獲
                      //要使主線程能夠捕獲這個(gè)RuntimeException請(qǐng)參見另外一篇文章
                      //地址:http://www.aygfsteel.com/fhtdy2004/archive/2009/08/07/290210.html

                      throw new RuntimeException(e);
                  }

                  System.out.println(getName() 
          + " join completed");
              }

          }


          public class Joining {

              
          public static void main(String[] args) {
                  Sleeper sleepy 
          = new Sleeper("Sleepy"1500),
                          grumpy 
          = new Sleeper("Grumpy"1500);
                  Joiner  dopey 
          = new Joiner("Dopey", sleepy), 
                          doc 
          = new Joiner("Doc",grumpy);
                  
          grumpy.interrupt();
                  //doc.interrupt();

              }

          }

          Sleeper是一個(gè)會(huì)睡上一段時(shí)間的Thread,至于睡多長時(shí)間,這要由構(gòu)造函數(shù)的參數(shù)決定。Sleeperrun( )sleep( )可以因時(shí)限到期而返回,也可以被interrupt( )打斷。catch語句在報(bào)告中斷的同時(shí),會(huì)一并報(bào)告isInterrupted( )當(dāng)有別的線程調(diào)用了本線程的interrupt( )時(shí),會(huì)設(shè)置一個(gè)標(biāo)記以表示這個(gè)這個(gè)線程被打斷了。當(dāng)本線程捕獲這個(gè)異常的時(shí)候,會(huì)清除這個(gè)標(biāo)志。所以catch語句會(huì)永遠(yuǎn)報(bào)告說isInterrupted( )是false。這個(gè)標(biāo)記是用來應(yīng)付其它情況的,或許在沒出異常的情況下,線程要用它來檢查自己是不是被中斷了。
          Joiner是另一個(gè)線程,它調(diào)用了Sleeperjoin( ),所以它要等Sleeper醒過來。main( )創(chuàng)建了兩個(gè)Sleeper分派給兩個(gè)Joiner。你會(huì)發(fā)現(xiàn),不論Sleeper是被打斷還是正常結(jié)束,Joiner都會(huì)隨Sleeper一道結(jié)束。





          2,如何終止一個(gè)線程:
          package test.thread.one;

          import java.util.Timer;
          import java.util.TimerTask;

          class CanStop extends Thread {
              
          // Must be volatile:
              private volatile boolean stop = false;

              
          private int counter = 0;

              
          public void run() {
                  
          while (!stop && counter < 100000{
                      System.out.println(counter
          ++);
                  }

                  
          if (stop)
                      System.out.println(
          "Detected stop");
              }


              
          public void requestStop() {
                  stop 
          = true;
              }

          }


          public class Stopping {
              
          public static void main(String[] args) {
                  
          final CanStop stoppable = new CanStop();
                  stoppable.start();
                  
          new Timer(true).schedule(new TimerTask() {
                      
          public void run() {
                          System.out.println(
          "Requesting stop");
                          stoppable.requestStop();
                      }

                  }
          500); // run() after 500 milliseconds
              }

          }

          stop必須是volatile的,這樣才能確保run( )方法能看到它(否則它會(huì)使用本地的緩存值)。這個(gè)線程的"任務(wù)"是打印10,000個(gè)數(shù)字,所以當(dāng)counter >= 10000或有人要它停下來的時(shí)候,它就結(jié)束了。注意requestStop( )不是synchronized,因?yàn)?span id="wmqeeuq" class="original_words">stop既是boolean(改成true是一個(gè)原子操作)又是volatile的。

          或者
          package test.thread.three;

          import java.util.Timer;
          import java.util.TimerTask;

          class CanStop extends Thread {
              
              
          private boolean stop = false;

              
          private int counter = 0;

              
          public void run() {
                  
          boolean done = false;
                  
          try{
                      Thread.sleep(
          100);
                  }
          catch(InterruptedException ie){
                      ie.printStackTrace();
                      
          //return;假如要使用interrupt來終止線程則在捕獲的InterruptedException中return
                  }

                  
          while (!getStopRequest() && counter < 100000 &&!done) {
                      System.out.println(counter
          ++);
                  }

                  
          if (getStopRequest())
                      System.out.println(
          "Detected stop");
              }

              
              
              
          public synchronized boolean getStopRequest(){
                  
          return stop;
              }


              
          public synchronized void requestStop() {
                  stop 
          = true;
              }

          }


          public class Stopping {
              
          public static void main(String[] args) {
                  
          final CanStop stoppable = new CanStop();
                  stoppable.start();
                  
          new Timer(true).schedule(new TimerTask() {
                      
          public void run() {
                          System.out.println(
          "Requesting stop");
                          stoppable.requestStop();
                      }

                  }
          500); // run() after 500 milliseconds
              }

          }


          打斷受阻的線程
          有時(shí)線程受阻之后就不能再做輪詢了,比如在等輸入,這時(shí)你就不能像前面那樣去查詢旗標(biāo)了。碰到這種情況,你可以用Thread.interrupt( )方法打斷受阻的線程:

          //: c13:Interrupt.java
          // Using interrupt() to break out of a blocked thread.
          import java.util.*;
          class Blocked extends Thread {
            
          public Blocked() {
              System.out.println(
          "Starting Blocked");
              start();
            }

            
          public void run() {
              
          try {
                
          synchronized(this{
                  wait(); 
          // Blocks
                }

              }
           catch(InterruptedException e) {
                System.out.println(
          "Interrupted");
              }

              System.out.println(
          "Exiting run()");
            }

          }

          public class Interrupt {
            
          static Blocked blocked = new Blocked();
            
          public static void main(String[] args) {
              
          new Timer(true).schedule(new TimerTask() {
                
          public void run() {
                  System.out.println(
          "Preparing to interrupt");
                  blocked.interrupt();
                  blocked 
          = null// to release it
                }

              }
          2000); // run() after 2000 milliseconds
            }

          }
           ///


          3.避免過多的同步,永遠(yuǎn)不要在循環(huán)外面調(diào)用wait

          為了避免死鎖的危險(xiǎn),在一個(gè)被同步的的方法或者代碼快中,永遠(yuǎn)不要放棄對(duì)客戶的限制。
          換句話說,在一個(gè)被同步的區(qū)域內(nèi)部,不要調(diào)用一個(gè)可被改寫的公有或受保護(hù)的方法(這樣的方法往往是一個(gè)抽象方法,但偶爾他們也會(huì)有一個(gè)默認(rèn)的實(shí)現(xiàn),)從包含該同步區(qū)域的類的角度來看,這樣的方法是一個(gè)外來者alien。這個(gè)類不知道該類會(huì)做什么事情,也控制不力它。客戶可以為這個(gè)外來方法提供一個(gè)實(shí)現(xiàn),并且在該方法中創(chuàng)建了一個(gè)線程,再回調(diào)到這個(gè)類中。然后,新建的線程試圖獲取原線程所擁有的那把鎖,這樣會(huì)導(dǎo)致新建的線程被阻塞。如果創(chuàng)建該線程的方法在等待這個(gè)線程完成這個(gè)任務(wù),則死鎖就形成了。


          Object.wait方法的作用是使一個(gè)線程等待某個(gè)條件。它一定是在一個(gè)同步區(qū)域中被調(diào)用,而且該同步區(qū)域鎖住了被調(diào)用的對(duì)象。下面是wait方法的標(biāo)準(zhǔn)模式:
          synchronized(obj){
                while(<condition does not hold>)
                      obj.wait();
                ...//perform action appropriate to condition
          }
          總是使用wait循環(huán)模式來調(diào)用wait方法。而不是if來調(diào)用。永遠(yuǎn)不要在循環(huán)的外面調(diào)用wait。循環(huán)被用于等待的前后測試條件

          package effective.java;

          import java.io.BufferedInputStream;
          import java.util.LinkedList;
          import java.util.List;

          public abstract class WorkQueue {
              
              
          private final List queue = new LinkedList();
              
              
          private boolean stopped = false;
              
              StringBuffer sb;
              BufferedInputStream bis;
              
              
          protected WorkQueue(){
                  
          new WorkerThread2().start();
              }

              
              
          public final void enqueue(Object workItem){
                  
          synchronized(queue){
                      queue.add(workItem);
                      queue.notify();
                  }

              }

              
              
          public final void stop(){
                  
          synchronized(queue){
                      stopped 
          = true;
                      queue.notify();
                  }

              }

              
              
          protected abstract void processItem(Object workItem)throws InterruptedException;
              
              
          //Broken - invokes alien method from synchronized block
              private class WorkerThread extends Thread{
                  
          public void run(){
                      
          while(true){
                          
          synchronized(WorkQueue.this.queue){
                              
          try{
                                  
          while(queue.isEmpty() && !stopped){
                                      queue.wait();
                                  }

                              }
          catch(InterruptedException ie){
                                  ie.printStackTrace();
                                  
          return;
                              }

                              
                              
          if(stopped)
                                  
          return;
                              Object workItem 
          = queue.remove(0);
                              
          try{
                                  processItem(workItem);
          //lock held
                              }
          catch(InterruptedException ie){
                                  System.out.println(
          "ddd"+ie);
                                  
          return;
                              }

                          }

                      }

                  }

              }

              
              
              
          //Alien method outside synchronized block -"open call"
              private class WorkerThread2 extends Thread{
                  
          public void run(){
                      
          while(true){
                          Object workItem 
          = null;
                          
          synchronized(WorkQueue.this.queue){
                              
          try{
                                  
          while(queue.isEmpty() && !stopped){
                                      queue.wait();
                                  }

                              }
          catch(InterruptedException ie){
                                  
          return;
                              }

                              
                              
          if(stopped)
                                  
          return;
                              workItem 
          = queue.remove(0);    
                          }

                          
                          
          try{
                              processItem(workItem);
          //No lock held
                          }
          catch(InterruptedException ie){
                              
          return;
                          }

                      }

                  }

              }

          }


          package effective.java;

          public class DisplayQueue extends WorkQueue {

              @Override
              
          protected void processItem(Object workItem) throws InterruptedException {
                  System.out.println(workItem);
                  System.out.println(
          "模擬此線程做耗時(shí)工作");
                  Thread.sleep(
          1000);
              }

              
              
          public static void main(String[] args){
                  WorkQueue wq 
          = new DisplayQueue();
                  
          for(int i=0;i<10;i++){
                      String s 
          = new String("object_"+i);
                      System.out.println(
          "main thread add " + s+" to queue");
                      wq.enqueue(s);
                      
          try{
                          Thread.sleep(
          500);
                      }
          catch(InterruptedException ie){
                          ie.printStackTrace();
                      }

                  }

                  
          //wq.stop();
              }


          }




          class DeadLockQueue extends WorkQueue{

              @Override
              
          protected void processItem(final Object workItem) throws InterruptedException {
                  
                  Thread child 
          = new Thread(){
                      
          public void run(){
                          
          //DeadLockQueue.this.enqueue(workItem);
                          System.out.println("在將對(duì)象入隊(duì)列 "+workItem);
                          enqueue(workItem);
                      }

                  }
          ;
                  child.start();
                  child.join();
          //dead lock
                  
              }

              
              
          }



          4.保持可運(yùn)行線程數(shù)量盡可能的少的主要技術(shù)是,讓每個(gè)線程做少量的工作,然后使用Object.wait等待某個(gè)條件發(fā)生,或者使用Thread.sleep()睡眠一段時(shí)間,線程不應(yīng)該忙-等busy-wait,即反復(fù)的檢查一個(gè)數(shù)據(jù)結(jié)構(gòu),以等待某些事件發(fā)生。除了使程序易受調(diào)度器的變化的影響外,忙等這種做法還會(huì)增加處理器的負(fù)擔(dān)
          busy-wait
          package effective.java;

          import java.util.LinkedList;
          import java.util.List;

          public abstract class WorkQueueBusyWait {
              
              
          private final List queue = new LinkedList();
              
              
          private boolean stopped = false;
              
              
          protected WorkQueueBusyWait(){
                  
          new WorkThread().start();
              }

              
              
          public final void enqueue(Object workItem){
                  
          synchronized(queue){
                      queue.add(workItem);
                  }

              }

              
              
          public final void stop(){
                  
          synchronized(queue){
                      stopped 
          = true;
                  }

              }

              
              
          protected abstract void processItem(Object workitem) throws InterruptedException;
              
              
          private class WorkThread extends Thread{
                  
          public void run(){
                      
          final Object QUEUE_IS_EMPTY = new Object();
                      
          while(true){
                          Object workItem 
          = QUEUE_IS_EMPTY;
                          
          synchronized(queue){
                              
          if(stopped)
                                  
          return;
                              
          if(!queue.isEmpty())
                                  workItem  
          = queue.remove(0);
                          }

                          
          if(workItem != QUEUE_IS_EMPTY){
                              
          try{
                                  processItem(workItem);
                              }
          catch(InterruptedException ie){
                                  ie.printStackTrace();
                                  
          return;
                              }

                          }

                      }

                  }

              }

          }


          class PingPongQueue extends WorkQueue{
              
          volatile int count=0;
              @Override
              
          protected void processItem(final Object workItem) throws InterruptedException {
                  count
          ++;
                  WorkQueue recipient 
          = (WorkQueue)workItem;
                  recipient.enqueue(
          this);
              }

              
          }


          package effective.java;

          public class WaitQueuePerf {

              
          /**
               * 
          @param args
               
          */

              
          public static void main(String[] args) {
                  
                  PingPongQueue q1 
          = new PingPongQueue();
                  PingPongQueue q2 
          = new PingPongQueue();
                  q1.enqueue(q2);
                  
                  
          try{
                      Thread.sleep(
          1000);
                  }
          catch(InterruptedException ie){
                      ie.printStackTrace();
                  }

                  
                  
          int count = q1.count;
                  
          try{
                      Thread.sleep(
          1000);
                  }
          catch(InterruptedException ie){
                      ie.printStackTrace();
                  }

                  System.out.println(q1.count
          -count);
                  q1.stop();
                  q2.stop();

              }


          }


          posted on 2009-08-22 11:07 Frank_Fang 閱讀(4831) 評(píng)論(0)  編輯  收藏 所屬分類: Java編程
          主站蜘蛛池模板: 江陵县| 黔南| 旅游| 错那县| 开江县| 嘉黎县| 青海省| 五原县| 于都县| 任丘市| 涿州市| 中方县| 梅河口市| 陈巴尔虎旗| 沛县| 茶陵县| 来安县| 常熟市| 江门市| 安泽县| 拉萨市| 武乡县| 黑水县| 南开区| 武城县| 台中县| 广平县| 绿春县| 山西省| 万安县| 宁阳县| 安顺市| 定边县| 白水县| 娱乐| 开远市| 剑川县| 沐川县| 莱芜市| 南通市| 治多县|