2013-11-02 22 views
7

nền

Tôi muốn hiểu tại sao một đoạn mã không không ném một NullPointerException.Tại sao mã này không ném NullPointerException?

Source Code

Xét đoạn mã sau:

public class Agent { 
    public List files = new ArrayList(); 

    public void deliver() { 
    if(files != null && files.iterator().hasNext()) { 
     File file = (File)files.iterator().next(); 
    } 

    files = new ArrayList(); 
    } 
} 

Phương pháp deliver được gọi là liên tục, trong khi các mã sau chạy trong một thread riêng biệt:

public void run() { 
    agent.files = null; 
    } 

Chỉ có một là duy nhất agent bản sao.

Vấn đề

Một NullPointerException là không bao giờ ném.

Tuy nhiên, khi deliver tạm dừng phương pháp, ngay cả đối với 0 mili giây, một NullPointerException được ném như mong đợi:

public void deliver() { 
    if(files != null) { 
     Thread.currentThread().sleep(0); 

     if(files.iterator().hasNext()) { 
     File file = (File)files.iterator().next(); 
     } 
    } 

    files = new ArrayList(); 
    } 

sự hiểu biết của tôi là có, về mặt lý thuyết, một điều kiện cuộc đua giữa kiểm tra files == null và gọi files.iterator().hasNext(). Trong thực tế, tôi không thể kích hoạt điều kiện chủng tộc mà không giới thiệu tạm dừng (tức là, tách kiểm tra null khỏi cuộc gọi phương thức tiếp theo).

Câu hỏi

Tại sao deliver phương pháp đầu tiên không ném một ngoại lệ khi kiểm tra và sử dụng rỗng được kết hợp trong báo cáo kết quả giống nhau không?

+1

Bạn có thể đăng đầu ra 'javap' ở những khu vực điều kiện xung quanh thích hợp không? – hexafraction

+8

Điều gì sẽ xảy ra khi bạn tạo 'tập tin'' dễ bay hơi? – OldCurmudgeon

Trả lời

5

Hai điều:

  1. Thread.sleep (0) vẫn dừng thi công (có khả năng nhiều hơn 0 mili giây). Về cơ bản, ngay cả một giấc ngủ 0 gây ra thực hiện trên thread đó để tạm dừng một thời gian ngắn, và sau đó khởi động lại. Điều này cho phép thread khác có cơ hội chạy và kết thúc, đó là lý do tại sao bạn có thể kích hoạt tình trạng cuộc đua.

  2. tệp phải là volatile, nếu không JVM được phép tối ưu hóa theo cách bạn không bao giờ thấy rằng giá trị thay đổi vì không nghĩ rằng nó cần duy trì sự nhất quán giữa các chuỗi.

+0

Điều này có nghĩa là JVM có thể xử lý việc kiểm tra null và việc sử dụng sau đó là một hoạt động nguyên tử, trừ khi được đặt rõ ràng là 'biến động'? –

+1

Một chủ đề có thể có một bản sao cục bộ của các biến như các tệp trong trường hợp của bạn. Do đó, việc đặt các tệp thành một thứ khác ngoài luồng đó sẽ không ảnh hưởng đến biến cục bộ. Chủ đề cuối cùng sẽ kiểm tra các sửa đổi bên ngoài, nhưng trong trường hợp của bạn có thể tại một điểm mà các tập tin luôn được đặt thành một giá trị. Dễ bay hơi sẽ đảm bảo rằng Thread _always_ kiểm tra các thay đổi bên ngoài. Vì vậy: không, nó sẽ không coi đây là một hoạt động nguyên tử, bạn chỉ có may mắn trong ví dụ của bạn trên máy của bạn trong JVM của bạn. – TwoThe

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