2011-08-11 27 views
5

Tôi đang cố gắng hiểu cách các luồng hoạt động trong Java và hiện đang điều tra cách thực hiện các chuỗi lặp có thể bị hủy bỏ. Dưới đây là các mã:Làm gián đoạn các chuỗi được lặp trong Java

public static void main(String[] args) throws Exception { 
    Thread t = new Thread() { 
     @Override 
     public void run() { 
      System.out.println("THREAD: started"); 
      try { 
       while(!isInterrupted()) { 
        System.out.printf("THREAD: working...\n"); 
        Thread.sleep(100); 
       } 
      } catch(InterruptedException e) { 
       // we're interrupted on Thread.sleep(), ok 

       // EDIT 
       interrupt(); 

      } finally { 
       // we've either finished normally 
       // or got an InterruptedException on call to Thread.sleep() 
       // or finished because of isInterrupted() flag 

       // clean-up and we're done 
       System.out.println("THREAD: done"); 
      }    
     } 
    }; 

    t.start(); 
    Thread.sleep(500); 
    System.out.println("CALLER: asking to stop"); 
    t.interrupt(); 
    t.join(); 
    System.out.println("CALLER: thread finished"); 
} 

Các chủ đề tôi tạo là indended bị gián đoạn sớm hay muộn. Vì vậy, tôi kiểm tra cờ isInterrupted() để quyết định xem tôi có cần tiếp tục và bắt InterruptedException để xử lý các trường hợp khi tôi đang hoạt động chờ (sleep, join, wait).

Những điều tôi muốn làm rõ là:

  1. Có tốt để sử dụng cơ chế gián đoạn cho các loại hình công việc? (so sánh với việc có volatile boolean shouldStop)
  2. Giải pháp này có đúng không?
  3. Tôi có nuốt InterruptedException bình thường không? Tôi không thực sự quan tâm đến đoạn mã mà ai đó đã yêu cầu sợi của tôi bị gián đoạn.
  4. Có cách nào ngắn hơn để giải quyết vấn đề này không? (Điểm chính là có vòng lặp 'vô hạn')

EDIT gia tăng cuộc gọi đến interrupt() trong đánh bắt cho InterruptedException.

+2

OK, nhưng không nên mở rộng Chủ đề vì không mở rộng chức năng của nó. Thực hiện một Runnable được sử dụng bởi một Thread chuẩn. –

Trả lời

4

Tôi trả lời là không. 3:

Về cơ bản, câu hỏi là: Ngoại lệ bị gián đoạn có mục đích gì? Nó cho bạn biết để ngăn chặn (ví dụ như ngủ) và trở về sớm.

Có hai cách đối phó với một InterruptedException:

  • rethrow nó, vì vậy các chủ đề vẫn bị gián đoạn
  • thiết Thread.currentThread.interrupt() một lần nữa và làm công việc dọn dẹp của bạn. Bằng cách này, bạn có thể chắc chắn rằng một phương pháp khác trong chuỗi của bạn bắt đầu chuyển sang chế độ ngủ sẽ ném lại một lần nữa

Đơn giản chỉ cần nuốt một số InterruptedException không phải là ý tưởng hay về mục đích gián đoạn cuối cùng. Nhưng bạn chỉ được yêu cầu làm gián đoạn để bạn vẫn có thời gian để dọn dẹp.

Trong trường hợp này, điều này có thể là 'quá mức' của bản thân, nhưng thông thường mã phức tạp hơn nhiều và làm sao bạn biết, một số mã tiếp theo trong Chủ đề này sẽ không gọi lại phương thức chặn?

EDIT

Nếu không tôi nghĩ rằng những gì bạn đang làm là tốt. Đối với tôi một chút ngạc nhiên, mặc dù, bởi vì tôi không bao giờ thấy bất cứ ai trong mã riêng của mình thực sự làm điều đó.

Và thú vị bài báo giải thích lý do tại sao có thể được tìm thấy ở đây: http://www.ibm.com/developerworks/java/library/j-jtp05236/index.html

+0

Vâng, tôi tin rằng rethrowing không phải là một trường hợp, vì tôi không thể ném từ thread 'run() '. Tôi có nên gọi là 'ngắt()'? – agibalov

+0

isInterrupted không đặt lại cờ bị gián đoạn. Và làm thế nào để bạn dừng một chủ đề chờ đợi hoặc ngủ trong một thời gian dài mà không làm gián đoạn nó? –

+0

Bạn nói đúng. bị gián đoạn() đang đặt lại ... –

2
  1. Vâng, không sao đâu. Bạn nên ghi lại cách một Thread/Runnable phải được dừng lại.Bạn có thể thêm một phương thức dừng chuyên dụng vào việc thực hiện Runnable của bạn để gói gọn cơ chế dừng. Hoặc sử dụng ngắt hoặc sử dụng giá trị boolean chuyên dụng hoặc cả hai.
  2. Vâng, ngoại trừ việc thực hành tốt là để khôi phục lại tình trạng ngắt khi bắt InterruptedException: Thread.currentThread().interrupt();
  3. Không, bạn nên khôi phục lại tình trạng ngắt
  4. Không mà tôi biết của
1

1) Các cách trong ví dụ của bạn là thích hợp hơn để sử dụng một lá cờ dễ bay hơi (đó là dư thừa kể từ khi bạn đã có cờ bị gián đoạn), theo Java Concurrency trong thực hành cuốn sách. Đó là cách InterruptedExceptions được dự định sẽ được sử dụng.

2) Có

3) bạn có thể ăn ngoại lệ miễn là bạn khôi phục trạng thái cờ ngắt. Ngoại lệ không đại diện cho một lỗi để ăn nó không mất bất kỳ thông tin, nó hoàn toàn là một phương tiện chuyển giao quyền kiểm soát. (Phục hồi trạng thái cờ ngắt là quan trọng đối với trường hợp bạn có cấu trúc điều khiển lồng nhau mà mỗi cần được thông báo rằng chuỗi đang hủy, ví dụ đơn giản giống như mẫu của bạn là tốt nhưng nếu thiếu nó sẽ không làm tổn thương gì cả.)

4) no

1

Bạn có thể sử dụng tốt để ngắt quãng. Bạn phải ném lại Thread.currentThread().interrupt() khi bắt. Dưới đây là một đoạn mã cho thấy lý do tại sao:

public class MyThread extends Thread { 
    private static boolean correct = true; 

    @Override 
    public void run() { 
     while (true) { 
      // Do Something 1 
      for (int i = 0; i < 10; i++) { // combined loop 
       // Do Something 2 
       try { 
        Thread.sleep(100); 
       } catch (InterruptedException ex) { 
        if (correct) 
         Thread.currentThread().interrupt(); // reinterrupting 
        System.out.println("First Catch"); 
        break; // for 
       } 
      } 
      try { 
       // Do Something 3 
       System.out.print("before sleep, "); 
       Thread.sleep(1000); 
       System.out.print("After sleep, "); 
      } catch (InterruptedException ex) { 
       if (correct) 
        Thread.currentThread().interrupt(); 
       System.out.println("Second catch"); 
       break; // while 
      } 
     } 
     System.out.println("Thread closing"); 
    } 

    private static void test() throws InterruptedException { 
     Thread t = new MyThread(); 
     t.start(); 
     Thread.sleep(2500); 
     t.interrupt(); 
     t.join(); 
     System.out.println("End of Thread"); 
    } 

    public static void main(String[] args) 
      throws InterruptedException { 
     test(); 
     correct = false; // test "bad" way 
     test(); 
    } 
} 

Một điều nữa là, Interruptions không luôn luôn làm việc khi chờ đợi vào InputStreams. Sau đó bạn có thể sử dụng (đối với một số) InterruptedIOException, nhưng nó sẽ không luôn luôn hoạt động. Để hiểu những trường hợp này, bạn có thể muốn thử đoạn mã này:

public class Mythread extends Thread { 
    private InputStream in; 

    public Mythread(InputStream in) { 
     this.in = in; 
    } 

    @Override 
    public void interrupt() { 
     super.interrupt(); 
     try { 
      in.close(); // Close stream if case interruption didn't work 
     } catch (IOException e) {} 
    } 

    @Override 
    public void run() { 
     try { 
      System.out.println("Before read"); 
      in.read(); 
      System.out.println("After read"); 
     } catch (InterruptedIOException e) { // Interruption correctly handled 
      Thread.currentThread().interrupt(); 
      System.out.println("Interrupted with InterruptedIOException"); 
     } catch (IOException e) { 
      if (!isInterrupted()) { // Exception not coming from Interruption 
       e.printStackTrace(); 
      } else { // Thread interrupted but InterruptedIOException wasn't handled for this stream 
       System.out.println("Interrupted"); 
      } 
     } 
    } 

    public static void test1() // Test with socket 
      throws IOException, InterruptedException { 
     ServerSocket ss = new ServerSocket(4444); 
     Socket socket = new Socket("localhost", 4444); 
     Thread t = new Mythread(socket.getInputStream()); 
     t.start(); 
     Thread.sleep(1000); 
     t.interrupt(); 
     t.join(); 
    } 

    public static void test2() // Test with PipedOutputStream 
      throws IOException, InterruptedException { 
     PipedInputStream in = new PipedInputStream(new PipedOutputStream()); 
     Thread t = new Mythread(in); 
     t.start(); 
     Thread.sleep(1000); 
     t.interrupt(); 
     t.join(); 
    } 

    public static void main(String[] args) throws IOException, InterruptedException { 
     test1(); 
     test2(); 
    } 
} 
Các vấn đề liên quan