2010-03-25 35 views
17

Goetz's Java Concurrency in Practice, trang 41, đề cập đến cách tham chiếu this có thể thoát trong khi xây dựng. A "không làm điều này" dụ:"Đối tượng được xây dựng không hoàn toàn" là gì?

public class ThisEscape { 
    public ThisEscape(EventSource source) { 
     source.registerListener(
      new EventListener() { 
       public void onEvent(Event e) { 
        doSomething(e); 
       } 
      }); 
    } 
} 

Đây this được "thoát" qua thực tế là doSomething(e) đề cập đến kèm theo ThisEscape dụ. Tình hình có thể được cố định bằng cách sử dụng phương pháp nhà máy tĩnh (đầu tiên xây dựng đối tượng đồng bằng, sau đó đăng ký người nghe) thay vì các nhà xây dựng công cộng (làm tất cả công việc). Cuốn sách tiếp tục:

Xuất bản đối tượng từ bên trong hàm tạo của nó có thể xuất bản đối tượng được xây dựng không đầy đủ. Điều này đúng ngay cả khi ấn phẩm là câu lệnh cuối cùng trong hàm tạo. Nếu thoát khỏi tài liệu tham khảo this trong khi xây dựng, đối tượng được coi là không được xây dựng đúng cách.

Tôi không hiểu rõ điều này. Nếu ấn phẩm là câu lệnh cuối cùng trong hàm tạo, thì không phải tất cả công việc xây dựng đã được thực hiện trước đó chưa? Làm thế nào đến là this không hợp lệ sau đó? Rõ ràng có một số voodoo xảy ra sau đó, nhưng những gì?

Trả lời

15

Kết thúc một hàm tạo là một vị trí đặc biệt về mặt đồng thời, đối với các trường cuối cùng. Từ section 17.5 của ngôn ngữ Java Specification:

Một đối tượng được coi là hoàn toàn khởi tạo khi nó kết thúc constructor. Một chuỗi chỉ có thể xem tham chiếu đến đối tượng sau khi đối tượng đó hoàn toàn được khởi tạo được đảm bảo để xem các giá trị được khởi tạo chính xác cho các trường cuối cùng của đối tượng đó.

Mô hình sử dụng cho trường cuối cùng là đơn giản. Đặt trường cuối cùng cho một đối tượng trong đối tượng của đối tượng đó. Không viết một tài liệu tham khảo cho đối tượng đang được xây dựng tại một địa chỉ nơi một sợi khác có thể xem nó trước khi hàm tạo của đối tượng là hoàn tất. Nếu điều này được theo sau, sau đó khi đối tượng được nhìn thấy bởi một chủ đề khác , chuỗi đó sẽ luôn thấy phiên bản được xây dựng chính xác của trường cuối cùng của đối tượng đó. Nó sẽ cũng xem các phiên bản của bất kỳ đối tượng nào hoặc các mảng được tham chiếu bởi các trường cuối cùng đó ít nhất là được cập nhật là trường cuối cùng là .

Nói cách khác, người nghe của bạn có thể sẽ thấy các trường cuối cùng với giá trị mặc định của họ nếu nó kiểm tra đối tượng trong chuỗi khác. Điều này sẽ không xảy ra nếu đăng ký người nghe xảy ra sau khi hàm tạo đã hoàn tất.

Xét về những gì đang xảy ra, tôi nghi ngờ có một rào cản bộ nhớ tiềm ẩn ở cuối của một hàm tạo, đảm bảo rằng tất cả các chuỗi "xem" dữ liệu mới; mà không có rào cản bộ nhớ đã được áp dụng, có thể có vấn đề.

+0

Ồ, thật đáng ngạc nhiên là các trường 'final', thường được coi là đồng thời thân thiện, là thủ phạm trong trường hợp này! –

+0

@Joonas: Đó là chà - chúng đồng thời thân thiện * nếu bạn đảm bảo tham chiếu không thoát khỏi hàm tạo *. Trong hầu hết các trường hợp, đó là một mức giá khá nhỏ để trả. –

+1

Thực tế, điều này áp dụng cho bất kỳ trường nào, không áp dụng cho các trường cuối cùng. –

2

Có một khoảng thời gian nhỏ nhưng hữu hạn giữa đầu cuối registerListener và hàm tạo trả lại. Một luồng khác có thể sử dụng vào lúc đó và cố gắng gọi doSomething(). Nếu thời gian chạy không quay trở lại mã của bạn tại thời điểm đó, đối tượng có thể ở trạng thái không hợp lệ.

Tôi không chắc chắn về java thực sự nhưng một ví dụ tôi có thể nghĩ đến là nơi có thể thời gian chạy sẽ chuyển vị trí trước khi quay lại với bạn.

Đó là một cơ hội nhỏ mà tôi cấp cho bạn.

6

Một vấn đề khác phát sinh khi bạn phân lớp ThisEscape và lớp con gọi hàm dẫn này. Việc ngầm định tham chiếu này trong EventListener sẽ có một đối tượng được xây dựng không đầy đủ.

+1

Cuộc gọi tốt. Đặc biệt, điều này có thể tạo ra các vấn đề nếu lớp con ghi đè các phương thức ảo từ 'ThisEscape' - những phương thức ghi đè này có thể được gọi trước khi trạng thái mà chúng yêu cầu đã được thiết lập. –

+1

Điều này đúng, nhưng ngoài chủ đề. –

+1

@Stephen C: Tôi nghĩ đây là một điểm khá tốt, chắc chắn không phải là chủ đề. –

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