2012-01-05 26 views
5

Tôi thay đổi giá trị được sử dụng để xác định khi nào một vòng lặp while kết thúc trong một chuỗi riêng biệt.
Tôi không muốn biết cách làm việc này. Nếu tôi truy cập thử nghiệm biến chỉ thông qua đồng bộ getters/setters nó hoạt động như mong đợi ..Hành vi lạ trong Java với truy cập không được đồng bộ hóa trong chương trình đa luồng

tôi lại có thể ngờ, nếu một số đọc/ghi lệnh bị mất do đồng thời chương trình đôi khi không chấm dứt, nhưng nó không bao giờ làm. Đó là điều gây nhầm lẫn cho tôi ..
Tôi muốn biết tại sao chương trình không bao giờ chấm dứt mà không có lệnh in. Và tôi muốn hiểu lý do tại sao lệnh in thay đổi bất cứ điều gì ..

 

    public class CustomComboBoxDemo { 
     public static boolean test = true; 
     public static void main(String[] args) { 
      Thread user =new Thread(){ 
       @Override 
       public void run(){ 
        try { 
         sleep(2000); 
        } catch (InterruptedException e) {} 
        test=false; 
       } 
      }; 
      user.start(); 
      while(test) { 
       System.out.println("foo"); //Without this line the program does not terminate.. 
      } 
     } 
    } 

+0

Xem: [Vòng lặp không thấy giá trị thay đổi mà không có bản in] (https://stackoverflow.com/questions/25425130/loop-doesnt-see-changed-value-without-a-print-statement) – Boann

Trả lời

8

Giải thích có khả năng nhất là biến chỉ đọc sau khi, chuyển while thành vòng lặp vô hạn (hoặc không có op). Vì bạn chưa khai báo testvolatile, trình biên dịch được phép thực hiện tối ưu hóa như vậy.

Khi bạn gọi hàm bên ngoài từ bên trong vòng lặp, trình biên dịch không còn có thể chứng minh rằng test vẫn không thay đổi trong lặp lặp lại và không thực hiện tối ưu hóa.

+1

Tôi tự hỏi, có phải trình biên dịch bytecode hay trình biên dịch JIT có thực hiện loại tối ưu đó không? – bezmax

+0

@Max: Trên hệ thống của tôi trình biên dịch bytecode không làm điều đó, vì vậy nó phải là trình biên dịch JIT. – NPE

+1

Btw, nó cũng có thể là nó liên tục đọc nó, nhưng làm như vậy từ một bộ nhớ cache (như một thanh ghi CPU) mà không bị ảnh hưởng đến ghi vào bộ nhớ chính. Đánh dấu trường là 'volatile' cũng sẽ sửa lỗi này. – yshavit

0

Tôi cho rằng đó là điều cần làm với cách xử lý IO. Nếu không có bản in, có thể bạn sẽ thấy ứng dụng java sử dụng tất cả thời gian CPU sẵn có; với khả năng in, có khả năng trễ IO sẽ mất đủ thời gian CPU để xử lý khác diễn ra.

Cách nhanh chóng để kiểm tra lý thuyết này là đặt printlns vào phương thức run() của chuỗi của bạn để xem liệu chuỗi có thực sự bao giờ thực thi hay không. Theo kinh nghiệm của tôi, các vòng trống vô tận gây ra rất nhiều hành vi lạ.

Điều đó nói rằng, nó xuất hiện để chấm dứt tốt trên máy trạm của tôi dưới JDK 1.6.0_10_b23

+0

Đồng ý với mcfinnigan. Thêm một số bản in gỡ lỗi vào chuỗi của bạn. Khi một cái gì đó không làm việc như mong đợi, luôn luôn làm một số công việc để chứng minh rằng giả định của bạn là chính xác, trong trường hợp này các thread riêng biệt đang làm việc như thiết kế. – Mitch

1

Nếu biến test không được định nghĩa như volatile, trình biên dịch có thể tối ưu hóa vòng lặp không chứa hoạt động vào một vòng lặp while(true) cho chính bạn chuỗi và chương trình không bao giờ kết thúc.

Nếu không, giá trị của biến số test thực sự được kiểm tra và khi chuỗi thứ hai của bạn thay đổi giá trị, thì chuỗi chính rời khỏi vòng while và chương trình của bạn chấm dứt.

0

Dường như vòng lặp của bạn đang được biên dịch không chính xác thành một sự chờ đợi bận. Thêm một từ khóa dễ bay hơi vào boolean của bạn sẽ sửa chữa 'vấn đề'.

0
public static boolean test = true; 
public static void main(String[] args) { 
    Thread user =new Thread(){ 
     @Override 
     public void run(){ 
      try { 
       sleep(2000); 
      } catch (InterruptedException e) {} 
      test=false; 
      System.out.println("Thread.end <"+test+">"); 
     } 
    }; 
    user.start(); 
    while(test); 
} 

Điều đó thật thú vị. Trình biên dịch có thể tối ưu hóa điều này trong khi vào một vòng lặp vô tận, không đọc giá trị tại mỗi vòng lặp.

Xác định kiểm tra như volatile bản sửa lỗi này và để cho chương trình của bạn chấm dứt

Btw: có thể bạn đã biết rằng bạn shoud sử dụng user.join() để chờ cho chủ đề đến kết thúc

0

Tôi không hiểu những gì bạn đang cố gắng làm bằng cách sử dụng mã bạn biết là không chính xác đồng bộ.

Như một số đã báo cáo, trên máy của họ, mã hoạt động khác với trên máy của bạn. Hành vi của mã được đồng bộ hóa kém là không xác định. Nó không có ý nghĩa để cố gắng hiểu những gì nó làm vì hành vi đó sẽ thay đổi với phiên bản JVM hoặc kiến ​​trúc.

Các vấn đề liên quan