2012-02-25 26 views

Trả lời

1

toán tử mới được phép trả lại giá trị trước khi hàm tạo của lớp kết thúc. Vì vậy, một biến có thể không đọc null nhưng chứa một cá thể lớp chưa được khởi tạo. Điều này xảy ra do sắp xếp lại byte.

Một số làm rõ: Từ góc độ chủ đề đơn lẻ, JVM được phép sắp xếp lại một số lệnh. Khi tạo một thể hiện truyền thống bạn sẽ nghĩ nó đi như thế này:

  • cấp phát bộ nhớ
  • chạy khởi tạo (constructor)
  • assign tham chiếu đến var

Trong khi trên thực tế JVM có thể làm một cái gì đó như:

  • cấp phát bộ nhớ
  • assign tham chiếu đến var
  • chạy khởi (constructor)

này có ưu điểm hiệu suất kể từ địa chỉ không cần phải được tra cứu lên một lần nữa. Từ một quan điểm chuỗi đơn lẻ, điều này không thay đổi thứ tự của logic. Chương trình của bạn hoạt động tốt. Nhưng điều này đặt ra một vấn đề trong mã đa luồng. Điều này có nghĩa là tham chiếu có thể được xuất bản trước khi hàm tạo đã chạy. Do đó bạn cần một quy tắc 'xảy ra-trước' để đảm bảo rằng cá thể được khởi tạo hoàn toàn. Khai báo các biến volatile dos thực thi các quy tắc xảy ra trước đó.

Thông tin thêm về sắp xếp lại: http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#reordering

+0

bạn có thể trích dẫn một nguồn? – musiKk

+0

@musiKk câu hỏi hay, tìm kiếm nó. –

+2

Tôi đã nghĩ rằng, thay vì điều này, tham chiếu có thể nói về việc xuất bản đối tượng bên trong hàm tạo (hoặc cái gì đó mà nó gọi). Tôi không thể nghĩ ra một trường hợp mà toán tử mới trả về một tham chiếu đối tượng trước khi hàm tạo được gọi là hoàn thành. – arcy

3

xem xét mã này:

public class World{ 
    public static Point _point; 

    public static void main(String[] args){ 
     new PointMaker().start(); 
     System.out.println(_point); 
    } 
} 

public class Point{ 
    private final int _x, _y; 

    public Point(int x, int y){ 
     _x = x; 
     World._point = this;//BAD: publish myself before I'm fully constructed 
     //some long computation here 
     _y = y; 
    } 

    public void toString(){ 
     return _x + "," + _y; 
    } 
} 

public class PointMaker extends Thread{ 
    public void run(){ 
     new Point(1, 1); 
    } 
} 

Point xuất bản bản thân trước khi thiết lập giá trị của _y, cuộc gọi đến println có thể mang lại "1,0" thay vì dự kiến ​​"1,1".

(Lưu ý rằng nó cũng có thể mang lại "null" nếu PointMaker + Point.<init> không nhận được đủ xa để thiết lập các lĩnh vực World._point trước khi cuộc gọi đến println thực thi.)

+1

Để chính xác, thậm chí có thể in "0,0". Nếu chúng ta rò rỉ tham chiếu này từ hàm tạo, thì JLS không thực hiện bất kỳ sự đảm bảo nào về kết quả cuối cùng. – Voo