2013-03-20 20 views
5

Tốt hơn bạn nên sử dụng thành ngữ khóa đã kiểm tra kép cho mẫu đơn? Hoặc một phương pháp đồng bộ?Có tối ưu để sử dụng thành ngữ khóa đã kiểm tra kép cho mẫu đơn?

ví dụ:

private static volatile ProcessManager singleton = null; 

public static ProcessManager getInstance() throws Exception { 

    if (singleton == null) { 
     synchronized (MyClass.class) { 
      if (singleton == null) { 
       singleton = new ProcessManager(); 
     } 
     } 
    } 
    return singleton; 

}

hoặc

private static processManager singleton = null; 

public synchronized static processManager getInsatnce() throws Exception { 

    if(singleton == null) { 
      singleton = new processManager(); 
    } 

    return singleton 
} 
+0

Có hai ifs lồng nhau mà không cần bất cứ điều gì ở giữa , như trong đoạn mã thứ hai của bạn, không có ý nghĩa gì cả. – Jesper

+4

Không có điều nào ở trên, như được giải thích trong [câu trả lời này] (http://stackoverflow.com/a/15498689/1103872) cho câu hỏi trước của riêng bạn. –

+0

trong ví dụ thứ hai của bạn, kiểm tra kép là không cần thiết (giả sử bạn không chạm vào thành viên singleton bất cứ nơi nào khác trong lớp học của bạn) vì bạn đã ở trong phần quan trọng – Grimmy

Trả lời

0

Về cơ bản, tùy chọn thứ hai của bạn thêm gì đảm bảo bổ sung.

Bạn kiểm tra thường xuyên hơn, nhưng truy cập đồng thời vẫn có thể xảy ra giữa chúng, vì vậy, bạn đang giảm khả năng xảy ra hai trường hợp, nhưng không loại bỏ nó.

6

Có ClassLoader làm công việc cho bạn:

/* 
    * This solution takes advantage of the Java memory model's guarantees about class initialization 
    * to ensure thread safety. Each class can only be loaded once, and it will only be loaded when it 
    * is needed. That means that the first time getInstance is called, mySingletonServiceLoader 
    * will be loaded and instance will be created, and since this is controlled by ClassLoaders, 
    * no additional synchronization is necessary. 
    */ 
    public static DocumentService getInstance() { 
     return mySingletonServiceLoader.INSTANCE; 
    } 

    private static class mySingletonServiceLoader { 
     static DocumentService INSTANCE = new DocumentService(); 
    } 
} 
0

lựa chọn đầu tiên.

Có khả năng tạo ra nhiều phiên bản của trường hợp duy nhất ...

trong getInstance() gọi dụ được kiểm tra cho null, và sau đó ngay lập tức được xây dựng nếu nó là null, và sau đó là instance Được trả lại.

Chủ đề phải an toàn.

Tham khảo this.

0

Tùy chọn đầu tiên là đúng đôi kiểm tra khóa thực hiện, nhưng nếu không có phương pháp nào hơn trong lớp ProcessManager nhưng getInstance sau đó tất cả các bạn cần là

public class ProcessManager { 
    private static ProcessManager instance; 
    static { 
     instance = new ProcessManager(); 
    } 

    private ProcessManager() { 
    } 

    public static ProcessManager getInstance() { 
     return instance; 
    } 
} 

lớp sẽ được nạp và khởi tạo trên ProcessManager đầu tiên .getInstance() invocation

0

Nếu tải lười là bắt buộc, tôi sẽ tuân thủ kiểm tra kép thay vì phương pháp được đồng bộ hóa. Cuối cùng, vấn đề là của volatile vs. synchronized:

Biến động, đơn giản buộc tất cả truy cập (đọc hoặc ghi) vào biến dễ bay hơi xảy ra với bộ nhớ chính, giữ hiệu quả biến dễ bay hơi ra khỏi bộ đệm CPU. Điều này có thể quan trọng đối với một số hành động mà nó chỉ đơn giản là yêu cầu rằng khả năng hiển thị của biến là chính xác và thứ tự truy cập không quan trọng.

Khi cá thể đã được khởi tạo, khối đồng bộ sẽ không được thực thi (nhưng đối với điều kiện chủng tộc). Chi phí đồng thời duy nhất được thanh toán là một lần đọc duy nhất cho biến dễ bay hơi.

Lưu ý rằng trong Effective Java Bloch nói rằng tải lĩnh vực dễ bay hơi trong một biến địa phương tăng cường hiệu suất (Tôi hiểu đó là bởi vì có rất ít biến động lần đọc)

public static ProcessManager getInstance() throws Exception { 
    ProcessManager result = singleton; 
    if (result == null) { 
    synchronized (MyClass.class) { 
     result = singleton; 
     if (result == null) { 
      singleton = result = new ProcessManager();    
     } 
    } 
    return result; 
} 
Các vấn đề liên quan