2017-01-17 12 views
5

tại sao luồng của tôi không thể dừng lại ???Chủ đề không thể dừng lại

class Threadz { 

    class runP implements Runnable { 
     int num; 
     private volatile boolean exit = false; 
     Thread t; 
     public runP() { 
      t = new Thread(this, "T1"); 
      t.start(); 
     } 

     @Override 
     public void run() { 
      while(!exit) { 
       System.out.println(t.currentThread().getName()+": "+num); 
       num++; 
       try { 
        t.sleep(200); 
       } catch(InterruptedException e) {} 
      } 
     } 
     public void stop() { 
      exit = true; 
     } 
    } 

    public static void main(String[] a) { 
     runP rp = new Threadz().new runP(); 
     if(rp.num == 1) {rp.stop();} 
    } 

} 

nếu tôi sử dụng rp.num == 0, thread có thể được dừng lại ngay lập tức. Nhưng, tại sao khi tôi thay đổi rp.num == x (x là bất kỳ số nào lớn hơn 0) thì luồng không thể dừng lại? hãy giúp tôi giải quyết vấn đề này ... cảm ơn vì đã giúp.

+2

Tôi đoán 'runP rp = new Threadz(). new runP(); 'đang tạo và bắt đầu luồng. Tuy nhiên, 'if (rp.num == 1) {rp.stop();}' ngay sau đó _might_ được thực hiện ngay trước khi luồng khác thực sự bắt đầu chạy vì vậy 'num' vẫn là 0. Ngoài ra, luồng có thể đã có chạy nhiều lần do đó việc kiểm tra 'rp.num == 1' là _very_ mong manh và có thể thường xuyên thất bại hơn là không. – Thomas

+0

Hãy xem xét sử dụng 'rp.num> 1' thay vì' rp.num == 1 'để dừng chuỗi của bạn để đảm bảo bạn không vô tình bỏ qua điều kiện dừng của bạn. – Quota

+0

Bạn cần sử dụng AtomicBoolean để thực sự giữ nguyên phương pháp này. Ngoài ra, bạn cần có thời gian hoàn hảo giữa cả hai luồng để nhấn ==. Bạn tốt hơn off với> – efekctive

Trả lời

3

Bởi vì mã này không được thực hiện trong phương thức run() của thread:

runP rp = new Threadz().new runP(); 
    if (rp.num == 1) { 
     rp.stop(); 
    } 

Nó hoạt động với 0 là giá trị mặc định của int là 0. Nhưng nó không nhất thiết phải đúng trong tất cả thực hiện của ứng dụng như các chủ đề của runP có thể chạy và tăng num trước khi kiểm tra: if (rp.num == 0)

Di chuyển trạng thái dừng trong method run của thread runP:

@Override 
public void run() { 
    while(!exit) { 
     System.out.println(t.currentThread().getName()+": "+num); 
     num++; 
     try { 
      t.sleep(200); 
     } catch(InterruptedException e) {} 

     if (rp.num == 1) { 
      exit = true; 
     } 
    } 
} 
+0

okay .. cố gắng tất cả các cách tôi có thể nhưng kết thúc với sự lựa chọn này ... cảm ơn bro – BeginnerToJava

+0

btw nếu tôi có 2 chủ đề, làm thế nào để vượt qua var từ 1 thread khác? Bạn có thể cho tôi biết làm thế nào? – BeginnerToJava

+0

Bạn được chào đón :) Không cần phải vượt qua biến, chỉ cần chia sẻ nó giữa các chủ đề của bạn. Bạn có thể sử dụng một AtomicInteger mà bạn chia sẻ giữa các luồng runP và cung cấp AtomicInteger trong hàm khởi tạo của runP. Nó sẽ là tốt. – davidxxx

0

Tôi chắc chắn nếu bạn chạy chương trình nhiều lần, Nó sẽ là một trường hợp khi chương trình thực sự dừng lại.

Lý do là tại thời điểm bạn chạy chương trình có nhiều hơn nữa cơ hội thực hiện

if(rp.num == 1) {rp.stop();} 

trước num++ trong phương pháp run() của bạn thay đổi giá trị.

Tuy nhiên, tình cờ bạn có thể gặp trường hợp vòng lặp trong phương thức chạy của bạn được thực thi trước đó nếu câu lệnh trong phương thức chính của bạn.

một cách để đảm bảo điều này xảy ra là liên tục kiểm tra điều kiện:

ví dụ:

public static void main(String[] a) { 
    runP rp = new Threadz().new runP(); 

    while(true){ 
     if(rp.num == 1) { 
     rp.stop(); 
     break; 
     } 
    } 
} 
0

Tuyên bố bên dưới được thực thi trước khi bắt đầu thực hiện phương thức chạy.

if(rp.num == 1) {rp.stop();} 

Thêm Thread.sleep trước câu lệnh trên, nó hoạt động tốt vì nó sẽ thực thi câu lệnh này sau khi bắt đầu vòng lặp.

public static void main(String[] a) { 
    runP rp = new Threadz().new runP(); 
    try { 
     Thread.sleep(2000); 
    } catch (InterruptedException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    if(rp.num > 1) {rp.stop();} 
} 

Tôi đã thực hiện> 1 để kiểm tra.

0

Kiểm tra rp.num == 1 sẽ phải xảy ra chính xác tại thời điểm mà rp.num chính xác là một, điều này khá khó xảy ra.

Trong phương thức main của bạn, bạn bắt đầu một chuỗi gia tăng num cứ 200 ms một lần. Sau đó, bạn kiểm tra xem num == 1, nhưng khi chính xác mã này được thực thi tùy thuộc vào nhiều yếu tố bạn không thể thực sự kiểm soát (lập lịch của hệ điều hành, v.v ...). Điều này có thể sau 10 ms (trong đó giá trị sẽ là 1), nhưng cũng có thể sau 300 ms (khi giá trị đã là 2). Ngoài ra khi các chủ đề được chính xác bắt đầu là không chắc chắn. Vì vậy, nó cũng có thể là chủ đề của bạn chỉ bắt đầu sau khi thử nghiệm. Bạn có thể dễ dàng kiểm tra điều này bằng cách thay thế séc if(rp.num == 1) {rp.stop()}; bằng lệnh in đơn giản System.out.println(rp.num). Nếu bạn chờ thêm một chút trước khi in, bạn có thể có cảm giác tốt hơn về những gì tôi đang nói đến.

Giả sử bạn muốn ngăn chặn một Runnable từ bên ngoài, tôi đề nghị sử dụng một cái gì đó giống như Observer pattern:

class MyRunnable implements Runnable { 

    private final MyListener l; 
    private volatile boolean exit; 
    int num; 

    public MyRunnable(MyListener l) { 
     this.l = l; 
     exit = false; 
    } 

    @Override 
    public void run() { 
     while(!exit) { 
      System.out.println(t.currentThread().getName()+": "+num); 
      l.check(num++); 
      try { 
       t.sleep(200); 
      } catch(InterruptedException e) {} 
     } 
    } 

    public void stop() { 
     exit = true; 
    } 
} 

class MyListener { 

    private final threshold; 

    public MyListener(int x) { 
     this.threshold = x; 
    } 

    public void check(MyRunnable r, int num) { 
     if (num >= threshold) 
      r.stop(); 
    } 

} 

và phương pháp chính của bạn sẽ giống như

public static void main(String[] args) { 
    MyListener l = new MyListener(1); 
    Runnable r = new MyRunnable(l); 
    new Thread(r).start(); 
} 
Các vấn đề liên quan