2012-02-29 46 views
10

Tôi hy vọng điều này sẽ là đủ thông tin, vì vậy, thông tin này sẽ xuất hiện. Nếu bạn cần thêm thông tin, hãy để ý trong phần bình luận.Khi nào cần sử dụng đồng bộ trong Java

Tôi có một lớp học có hai lớp bên trong. Mỗi lớp bên trong có hai phương thức gọi một phương thức trong lớp ngoài. Vì vậy, nó trông như thế này:

public OuterClass { 
    private boolean outerMethodHasBeenCalled = false; 

    private void outerMethod() { 
     if(!outerMethodHasBeenCalled) { 
      // do stuff 
     } 

     outerMethodHasBeenCalled = true; 
    } 

    private FirstInnerClass { 
     public void someMethod() { 
      outerMethod(); 
     } 
    } 

    private SecondInnerClass { 
     public void someOtherMethod() { 
      outerMethod(); 
     } 
    } 
} 

Điều quan trọng cần lưu ý là:

  • này là dành cho một ứng dụng Android. Các trường hợp của FirstInnerClassSecondInnerClass được chuyển đến WebView dưới dạng giao diện JavaScript, vì vậy, someMethodsomeOtherMethod có thể được gọi bất kỳ lúc nào, không theo thứ tự cụ thể.
  • Tôi hiện đang gặp sự cố với mã hiện tại (không có từ khóa được đồng bộ hóa) trong đó outerMethod được gọi khá nhiều vào cùng một thời điểm (tôi in một thông điệp tường trình và chúng được đặt thời gian vào 1000 giây) các đối tượng khác nhau. Ứng dụng của tôi sau đó 'thực hiện công cụ' hai lần vì outerMethodHasBeenCalled vẫn sai khi outerMethod được gọi. Điều này không ổn, và đó chính xác là những gì tôi đang cố gắng ngăn chặn. Ứng dụng của tôi chỉ nên 'thực hiện' một lần và chỉ một lần: lần đầu tiên được gọi là outerMethod.
  • Có vẻ như tôi có nhiều phiên bản OuterClass nhưng hãy yên tâm rằng chỉ có một phiên bản là OuterClass.

Điều quan trọng là ứng dụng của tôi 'thực hiện' chỉ là lần đầu tiên outerMethod được gọi (tôi hy vọng điều đó hiển nhiên bây giờ). Tất cả các cuộc gọi tiếp theo về cơ bản bị bỏ qua. Bất kỳ lớp bên trong nào cũng gọi số outerMethod trước - không quan trọng.

Vì vậy, việc sử dụng từ khóa được đồng bộ hóa trong trường hợp này có thích hợp không?

Trả lời

19

Yup, cho những gì bạn đã đặt ra ở trên, tôi muốn đi với:

private synchronized void outerMethod() { 
... 
} 

Lưu ý, điều này sẽ có tác dụng phụ chặn một trong những người gọi đến khi outerMethod() hoàn tất. Nếu đó là chấp nhận được, mát mẻ. Nếu mục đích chỉ đơn thuần là các mã trong outerMethod() được chạy một lần, nó là OK cho người gọi thứ hai không được trì hoãn nếu người gọi đầu tiên đang chạy outerMethod(), bạn có thể xem xét:

public OuterClass { 
    private AtomicBoolean outerMethodHasBeenCalled = new AtomicBoolean(); 

    private void outerMethod() { 
     if (outerMethodHasBeenCalled.compareAndSet(false, true)) { 
      // do stuff 
     } 
    } 
... 

Xem JavaDoc for AtomicBoolean để bẻ khóa những gì đang xảy ra ở đó (giả sử nó có sẵn trong Java của Android).

+9

+1 cho AtomicBoolean, đã học được điều gì đó mới :) – quaylar

7

Quấn tất cả mọi thứ trong outerMethod mà bạn muốn chạy một lần duy nhất trong một khối đồng bộ:

private void outerMethod() { 
    synchronized (this) { 
     if(!outerMethodHasBeenCalled) { 
      // do stuff 
     } 

     outerMethodHasBeenCalled = true; 
    } 
} 

Bằng cách đó, lần đầu tiên phương pháp này được gọi là, chỉ có một chủ đề sẽ được phép vào khối đồng bộ tại một thời gian. Người đầu tiên sẽ thực thi mã trong câu lệnh if, sau đó đặt outerMethodHasBeenCalled thành true. Các chủ đề khác sẽ thấy rằng nó là đúng, và bỏ qua nếu mã.

+0

bạn cũng không cần phải đặt cờ 'biến động' (để các Chủ đề khác có thể thấy được sự thay đổi đáng tin cậy)? Có thể sử dụng AtomicBoolean để an toàn. – Thilo

+1

@Thilo: Nếu tất cả các truy cập vào cờ nằm ​​bên trong các khối được đồng bộ hóa, không cần sử dụng 'biến động'.Mô hình bộ nhớ Java đảm bảo rằng các thay đổi sẽ được hiển thị. AtomicBoolean và dễ bay hơi rất hữu ích khi bạn không muốn có chi phí của một khối đồng bộ đầy đủ, mặc dù chúng phức tạp hơn để sử dụng. – Avi

+2

@Thilo không có bạn không cần phải, nếu nơi duy nhất mà outerMethodHasBeenCalled được truy cập là trong outerMethod. Từ khóa được đồng bộ biểu thị một hàng rào đồng bộ hóa bộ nhớ. Đọc thông số VM trên từ khóa được đồng bộ hóa. BTW, xin đừng làm công cụ chỉ 'để được ở bên an toàn'. Hiểu chính xác những gì bạn đang viết và những tác động. Các lập trình viên khác đi vào mã của bạn sau khi bạn hiểu DO sẽ tạm thời bị theo dõi bên cạnh để tìm hiểu lý do tại sao một cấu trúc được sử dụng, ví dụ: "Anh ta phải sử dụng dễ bay hơi vì một lý do, tôi không thấy gì?" – brettw

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