2013-05-20 33 views
10

Giả sử bạn có mã này:Trong khối Java được đồng bộ hóa, có thể hiển thị trên tất cả các trường hoặc chỉ biến được đồng bộ hóa?

private String cachedToken; 
private final Object lockObject = new Object(); 

.... 


retrieveToken(){ 
synchronized(lockObject){ 
    if (cachedToken == null){ 
    cachedToken = goGetNewToken(); 
    } 
    return cachedToken; 
} 
} 

Liệu ghi vào cachedToken được hiển thị cho tất cả các chủ đề đã bị khóa trên lockObject?

+0

Vâng, đó là vấn đề ... Nhưng việc ghi có thể xảy ra với bộ nhớ cache l1 hoặc l2 của CPU và không được chuyển sang bộ nhớ chính trước khi một chuỗi khác lấy khóa. –

+0

Điều đó không đúng. Nếu một luồng khác khóa trên 'lockObject' sau khi một luồng khác viết thì lá, chuỗi nhập sẽ thấy ghi. –

+0

Lưu ý: ghi vào "biến đồng bộ" thường xuyên * xấu *. Mã được đồng bộ hóa trên một đối tượng, không phải là một biến. Nếu biến được thay đổi giữa dòng để tham chiếu một đối tượng khác, nhiều khối được đồng bộ hóa trên đối tượng được tham chiếu bởi biến đó có thể thực thi đồng thời. –

Trả lời

7

Có. Đồng bộ hóa trên lockObject thiết lập một Happens Before Relationship (aka thiết lập một rào cản bộ nhớ). Điều này có nghĩa rằng tất cả các chủ đề mà sau đó nhận được khóa sẽ thấy bất kỳ thay đổi nào đã xảy ra trong khi khóa được giữ trước đó.

Đối với những gì đáng giá, mặc dù, việc triển khai lười biếng của bạn là thiếu sót. Đây là cách thích hợp:

private volatile String cachedToken; 

retrieveToken() { 
    if (cachedToken == null) { 
     synchronized(lockObject) { 
      if (cachedToken == null) { 
       cachedToken = goGetNewToken(); 
      } 
     } 
    } 
    return cachedToken 
} 

Bằng cách này bạn chỉ phải lấy khóa một số lần nhỏ khi Chủ đề bắt đầu yêu cầu. Sau đó, cachedToken sẽ không rỗng, và bạn sẽ không cần phải đồng bộ hóa.

+0

Và rào cản bộ nhớ đó sẽ bao gồm bất kỳ trường nào được chạm vào, không chỉ đối tượng mà tôi đã đồng bộ hóa? –

+0

@Tom McIntyre Cách làm của bạn thực sự không an toàn. Xem xét điều này: http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html – Mik378

+1

có, nếu không, trạng thái đồng thời chia sẻ sẽ còn khó khăn hơn so với hiện tại! –

5

Tất nhiên, synchronize đảm bảo hai điều:

  • Atomicity
  • rào cản Memory (những gì bạn mong đợi trong trường hợp của bạn) trên toàn bộ đối tượng

Trong khi ví dụ, volatile đảm bảo hàng rào bộ nhớ nhưng không xử lý nguyên tử.

+0

ngoài việc đọc và viết dài hoặc gấp đôi, nơi mà dễ bay hơi đảm bảo nguyên tử. –

+0

@Tom McIntyre Có, nhưng không phải do từ khóa 'volatile'. – Mik378

+0

ý của bạn là 'không phải do chính từ khóa dễ bay hơi'? –

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