2010-03-26 28 views
9

Tôi có một số câu hỏi về sự khẳng định của Java.Vấn đề về chuyển nhượng Java - Đây có phải là nguyên tử không?

  • Strings

Tôi đã có một lớp:

public class Test { 
private String s; 

public synchronized void setS(String str){ 
    s = s + " - " + str; 
} 

public String getS(){ 
    return s; 
} 
} 

Tôi đang sử dụng "đồng bộ" trong setter của tôi, và tránh nó trong getter của tôi, bởi vì trong ứng dụng của tôi, có rất nhiều dữ liệu và rất ít cài đặt. Cài đặt phải được đồng bộ hóa để tránh sự không thống nhất. Câu hỏi của tôi là: đang nhận và thiết lập một biến nguyên tử? Tôi có nghĩa là, trong một môi trường đa luồng, Thread1 sắp đặt biến s, trong khi Thread2 sắp sửa lấy "s". Có cách nào getter phương pháp có thể nhận được một cái gì đó khác với giá trị cũ của s hoặc giá trị mới của s (giả sử chúng tôi đã có chỉ có hai chủ đề)? Trong ứng dụng của tôi nó không phải là một vấn đề để có được giá trị mới, và nó không phải là một vấn đề để có được một tuổi. Nhưng tôi có thể lấy thứ gì khác không?

  • Điều gì về việc nhận và đưa HashMap?

coi đây:

public class Test { 
     private Map<Integer, String> map = Collections.synchronizedMap(new HashMap<Integer, String>()); 

     public synchronized void setMapElement(Integer key, String value){ 
     map.put(key, value); 
     } 

     public String getValue(Integer key){ 
     return map.get(key); 
     } 
} 

là đưa và nhận nguyên tử? HashMap xử lý việc đưa một phần tử vào trong đó như thế nào? Trước tiên nó có xóa giá trị cũ và đặt giá trị hiện tại không? Tôi có thể nhận được khác hơn giá trị cũ hoặc giá trị mới?

Cảm ơn trước!

+0

+1 để chỉ định rằng người đọc không cần thấy giá trị mới nhất tuyệt đối. Tất nhiên, điều đó chắc chắn nên được ghi lại trong mã sản xuất. –

Trả lời

6

Trong trường hợp đầu tiên, String xảy ra an toàn cho việc xuất bản không an toàn (trong Mô hình bộ nhớ Java "mới"), vì vậy điều này là ổn.

Không phải là volatile có lý thuyết về một số vấn đề không có giá trị cập nhật, nhưng sau đó ý nghĩa của cập nhật không rõ ràng. Bạn có thể thay thế khóa bằng vòng lặp so sánh cát-trao đổi (CAS), nhưng điều đó có thể sẽ không cho bạn hiệu suất nhiều cho dù khóa có khả năng bị tranh cãi hay không.

Trong trường hợp HashMap, một bản đồ không đồng bộ không an toàn để đọc nếu có một luồng khác ghi vào nó, ngay cả một luồng văn bản. Trong thực tế, điều này đã được tìm thấy để dẫn đến vòng vô hạn trên các hệ thống sản xuất chạy phần mềm phổ biến. Mã trong câu hỏi thực sự sử dụng hai khóa cho bản đồ, nằm trên đầu trang (mặc dù bạn cần một khóa rõ ràng của cùng một khóa nếu sử dụng trình lặp). Không phải là final không ngăn lớp chứa có an toàn để xuất bản không an toàn. Nếu mapvolatile và bạn đã tạo bản đồ mới cho mọi put, thì điều đó có thể được thực hiện để an toàn mà không đồng bộ hóa khi nhận được.

+0

Tôi đang sử dụng Collections.synchronizedMap. Nó có nguy hiểm không? Tôi đang sửa đổi cấu trúc chỉ trong những người định cư của tôi. Vì vậy, tôi đồng bộ hóa các phương pháp này, nhưng getters của tôi chỉ nhận được dữ liệu. Tôi có nên đồng bộ hóa chúng không? Tôi sợ rằng trong khi tôi đang thiết lập một giá trị trong HashMap một chủ đề khác muốn có được giá trị, và nó được một cái gì đó khác với giá trị cũ hoặc mới. – Bob

+0

'Collections.synchronizedMap' thêm đồng bộ hóa, như tên gọi của nó, nên bạn không phải làm như vậy. Bạn có thể có ý tưởng tốt hơn nếu nó viết mã của nó vào máy của bạn và sử dụng trực tiếp 'HashMap'. –

6

Thay vì gói HashMap của bạn vào thứ gì đó để đồng bộ hóa nó, hãy cân nhắc sử dụng java.util.concurrency.ConcurrentHashMap để thay thế.

Đây là phiên bản cập nhật của HashMap đảm bảo "Retrievals phản ánh kết quả của các hoạt động cập nhật mới nhất đã hoàn thành khi chúng khởi động".

3

Câu trả lời trước đó là chính xác khi chỉ với JVM mới (1,5+), phiên bản chuỗi là an toàn, liên quan đến tham nhũng dữ liệu. Và bạn dường như nhận thức được sự truy cập không đồng bộ; rằng các thay đổi không nhất thiết phải hiển thị thông qua getters.

Tuy nhiên: câu hỏi hữu ích hơn là: có lý do để đồng bộ hóa ở đây không? Nếu đây chỉ là vì quan tâm đến việc biết điều này, đó là tất cả tốt. Nhưng đối với mã thực, quy tắc chung của đọc và viết là nếu có thể có cả hai, cả hai cần được đồng bộ hóa. Vì vậy, mặc dù bạn có thể trong trường hợp này bỏ ra đồng bộ hóa (có khả năng có nghĩa là các chủ đề không thấy thay đổi các chủ đề khác thực hiện), có vẻ là ít lợi ích trong việc đó.

+0

Ứng dụng của tôi là một "công cụ blog" giống như ứng dụng. Tôi lưu trữ X đầu tiên (giả sử 10) của các mục nhập mới được tạo trong một biến. Nó không phải là một vấn đề mà người dùng không nhận được phiên bản cập nhật của các mục nhập, bởi vì họ có thể làm mới trang nếu họ muốn. Tôi thực hiện khoảng 20 mục nhập trong một ngày (setter), nhưng tôi đã có hàng trăm ngàn khách truy cập mỗi ngày. Nó không phải là hiệu quả (tôi nghĩ) để đồng bộ hóa các phương thức getter (tôi đã có khá nhiều phương thức getter như trên). (Không, tôi chưa có hàng trăm ngàn khách truy cập mỗi ngày, nhưng tôi muốn ứng dụng của mình có thể xử lý điều đó) – Bob

+5

Lưu ý rằng không chỉ là vấn đề người dùng làm mới trang. Trong mô hình bộ nhớ Java, nếu không có sự đồng bộ hóa giữa chủ đề setter và luồng getter, có thể là thread getter sẽ * không bao giờ * nhận được giá trị cập nhật. Điều này nghe giống như một loại tối ưu hóa sớm đối với tôi. Làm cho nó chính xác đầu tiên. Nếu sau này bạn thấy rằng việc đồng bộ hóa thực sự hạn chế thông lượng của bạn, thì bạn có thể xem xét các cách tốt hơn để xử lý nó. –

+0

"có thể là chuỗi getter sẽ không bao giờ nhận được giá trị cập nhật." Làm thế nào mà? Tôi chỉ không nhận được nó. "35 sec 300 millisec" Tôi nhận được giá trị, đó là giá trị cũ. "35 sec 500 millisec" Tôi đặt giá trị, hơn "50 sec xxx millisec" Tôi cố gắng lấy giá trị mới? Làm thế nào đến nó là có thể tôi sẽ không nhận được giá trị mới bao giờ? – Bob

1

Trong môi trường nhiều luồng, bạn sẽ cần phải đồng bộ hóa bộ thu thập để đảm bảo khách hàng thấy giá trị cập nhật nhất của s.

+0

làm cho biến "dễ bay hơi" sẽ chỉ có hiệu quả và không yêu cầu phí đồng bộ hóa –

+2

'volatile' có tính năng đồng bộ hóa riêng được tích hợp sẵn. – Bombe

2

Có lẽ Read Write Lock có thể giải quyết được sự cố của bạn?

Hãy xem tài liệu hướng dẫn của nó:

Một read-write lock cho phép một mức độ lớn hơn đồng thời trong việc tiếp cận dữ liệu chia sẻ hơn cho phép một khóa loại trừ lẫn nhau. Nó khai thác thực tế là mặc dù chỉ có một luồng đơn tại một thời điểm (một luồng ghi) có thể sửa đổi dữ liệu được chia sẻ, trong nhiều trường hợp, bất kỳ số luồng nào cũng có thể đọc dữ liệu (do đó đọc luồng). Về lý thuyết, sự gia tăng đồng thời được cho phép bằng cách sử dụng khóa đọc ghi sẽ dẫn đến cải thiện hiệu suất trong việc sử dụng khóa loại trừ lẫn nhau. ....

+0

+1 nhưng tôi sẽ ngạc nhiên nếu các bộ sưu tập được đồng bộ hóa chưa sử dụng nó. – HRJ

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