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

          interrupt

          public void interrupt()
          中斷線程。

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

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

          如果該線程在可中斷的通道上的 I/O 操作中受阻,則該通道將被關閉,該線程的中斷狀態將被設置并且該線程將收到一個 ClosedByInterruptException。

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

          如果以前的條件都沒有保存,則該線程的中斷狀態將被設置。

           

          拋出:
          SecurityException - 如果當前線程無法修改該線程

          interrupted

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

           

          返回:
          如果當前線程已經中斷,則返回 true;否則返回 false
          另請參見:
          isInterrupted()

          isInterrupted

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

           

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

          t.interrupt()不會中斷正在執行的線程,只是將線程的標志位設置成true。但是如果線程在調用sleep(),join(),wait()方法時線程被中斷,則這些方法會拋出InterruptedException,在catch塊中捕獲到這個異常時,線程的中斷標志位已經被設置成false了,因此在此catch塊中調用t.isInterrupted(),Thread.interrupted()始終都為false,
          而t.isInterrupted與Thread.interrupted()的區別是API中已經說明很明顯了,Thread.interrupted()假如當前的中斷標志為true,則調完后會將中斷標志位設置成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);//設置成100比主線程中的500要小
                  }
          catch(InterruptedException ie){
                      ie.printStackTrace();
                      
          //return;假如要使用interrupt來終止線程則在捕獲的InterruptedException中return
                  }

                  
          while (counter < 100000 &&!done) {
                      System.out.println(counter
          ++);
                      
          //在主線程中調用stoppable.interrupt()之前為false,假如之后沒有調用Thread.interrupted()則一直為true,
                      
          //否則為第一次為true,調用Thread.interrupted之后為false
                      System.out.println("in thread stoppable.isInterrupted() "+isInterrupted());
                      
                      
          //System.out.println("stoppable.isInterrupted() "+Thread.interrupted());////在主線程中調用stoppable.interrupt()之前為false,之后只有第一個會顯示為true,之后全為false
                      
                      
          //調用Thread.interrupted()一次會清除線程的中斷標志位,因此以后都為false
                      if(Thread.interrupted()==true){
                          
          try{
                              
          //Thread.interrupted()會清除中斷標志位,顯然這里面只會調用一次
                              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();
          //不會中斷正在執行的線程,原因是因為interrupt()方法只設置中斷狀態標志位為true
                          System.out.println("in timer stoppable.isInterrupted() "+stoppable.isInterrupted());
                      }

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

          }



          2,關于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,也不會被主線程捕獲
                      //要使主線程能夠捕獲這個RuntimeException請參見另外一篇文章
                      //地址: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是一個會睡上一段時間的Thread,至于睡多長時間,這要由構造函數的參數決定。Sleeperrun( )sleep( )可以因時限到期而返回,也可以被interrupt( )打斷。catch語句在報告中斷的同時,會一并報告isInterrupted( )當有別的線程調用了本線程的interrupt( )時,會設置一個標記以表示這個這個線程被打斷了。當本線程捕獲這個異常的時候,會清除這個標志。所以catch語句會永遠報告說isInterrupted( )是false。這個標記是用來應付其它情況的,或許在沒出異常的情況下,線程要用它來檢查自己是不是被中斷了。
          Joiner是另一個線程,它調用了Sleeperjoin( ),所以它要等Sleeper醒過來。main( )創建了兩個Sleeper分派給兩個Joiner。你會發現,不論Sleeper是被打斷還是正常結束,Joiner都會隨Sleeper一道結束。





          2,如何終止一個線程:
          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( )方法能看到它(否則它會使用本地的緩存值)。這個線程的"任務"是打印10,000個數字,所以當counter >= 10000或有人要它停下來的時候,它就結束了。注意requestStop( )不是synchronized,因為stop既是boolean(改成true是一個原子操作)又是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
              }

          }


          打斷受阻的線程
          有時線程受阻之后就不能再做輪詢了,比如在等輸入,這時你就不能像前面那樣去查詢旗標了。碰到這種情況,你可以用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.避免過多的同步,永遠不要在循環外面調用wait

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


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

          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(
          "模擬此線程做耗時工作");
                  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("在將對象入隊列 "+workItem);
                          enqueue(workItem);
                      }

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

              
              
          }



          4.保持可運行線程數量盡可能的少的主要技術是,讓每個線程做少量的工作,然后使用Object.wait等待某個條件發生,或者使用Thread.sleep()睡眠一段時間,線程不應該忙-等busy-wait,即反復的檢查一個數據結構,以等待某些事件發生。除了使程序易受調度器的變化的影響外,忙等這種做法還會增加處理器的負擔
          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 閱讀(4832) 評論(0)  編輯  收藏 所屬分類: Java編程
          主站蜘蛛池模板: 泸西县| 合山市| 玉溪市| 阳曲县| 张家界市| 通辽市| 河南省| 玉山县| 呈贡县| 错那县| 塘沽区| 万山特区| 六枝特区| 峨边| 石棉县| 大邑县| 莱阳市| 徐州市| 磴口县| 铜梁县| 芜湖市| 隆尧县| 梅州市| 怀远县| 勐海县| 元氏县| 泰安市| 桃园市| 邳州市| 德兴市| 格尔木市| 潞城市| 临安市| 剑河县| 竹北市| 南皮县| 阿克| 文化| 资溪县| 日照市| 呼图壁县|