Có phải ConcurrentHashMap.get()
được bảo đảm để xem trước ConcurrentHashMap.put()
theo chuỗi khác nhau? Mong đợi của tôi là có nghĩa là, và đọc JavaDocs dường như chỉ ra như vậy, nhưng tôi 99% tin rằng thực tế là khác nhau. Trên máy chủ sản xuất của tôi, bên dưới có vẻ như đang xảy ra. (Tôi đã bắt gặp nó với khai thác gỗ.) MãConcurrentHashMap.get() có được đảm bảo để xem một ConcurrentHashMap.put() trước đó bằng các luồng khác nhau không?
Pseudo dụ:
static final ConcurrentHashMap map = new ConcurrentHashMap();
//sharedLock is key specific. One map, many keys. There is a 1:1
// relationship between key and Foo instance.
void doSomething(Semaphore sharedLock) {
boolean haveLock = sharedLock.tryAcquire(3000, MILLISECONDS);
if (haveLock) {
log("Have lock: " + threadId);
Foo foo = map.get("key");
log("foo=" + foo);
if (foo == null) {
log("New foo time! " + threadId);
foo = new Foo(); //foo is expensive to instance
map.put("key", foo);
} else
log("Found foo:" + threadId);
log("foo=" + foo);
sharedLock.release();
} else
log("No lock acquired");
}
gì dường như xảy ra là thế này:
Thread 1 Thread 2
- request lock - request lock
- have lock - blocked waiting for lock
- get from map, nothing there
- create new foo
- place new foo in map
- logs foo.toString()
- release lock
- exit method - have lock
- get from map, NOTHING THERE!!! (Why not?)
- create new foo
- place new foo in map
- logs foo.toString()
- release lock
- exit method
Vì vậy, đầu ra của tôi trông như thế này:
Have lock: 1
foo=null
New foo time! 1
[email protected]
Have lock: 2
foo=null
New foo time! 2
[email protected]
Chuỗi thứ hai không ngay lập tức nhìn thấy giá trị đặt! Tại sao? Trên hệ thống sản xuất của tôi, có nhiều chủ đề hơn và tôi chỉ thấy một luồng, luồng đầu tiên ngay sau chuỗi 1, có vấn đề.
Tôi thậm chí đã cố gắng thu hẹp mức đồng thời trên ConcurrentHashMap xuống 1, không phải là vấn đề. Ví dụ:
static ConcurrentHashMap map = new ConcurrentHashMap(32, 1);
Tôi sẽ làm gì sai? Mong đợi của tôi? Hoặc là có một số lỗi trong mã của tôi (phần mềm thực sự, không phải ở trên) đang gây ra điều này? Tôi đã đi qua nó nhiều lần và chắc chắn 99% tôi đang xử lý khóa một cách chính xác. Tôi thậm chí không thể hiểu được một lỗi trong ConcurrentHashMap
hoặc JVM. Vui lòng lưu tôi từ chính tôi.
chi tiết cụ thể Gorey mà có thể có liên quan:
- quad-core 64-bit Xeon (DL380 G5)
- RHEL4 (
Linux mysvr 2.6.9-78.0.5.ELsmp #1 SMP
...x86_64 GNU/Linux
) - Java 6 (
build 1.6.0_07-b06
,64-Bit Server VM (build 10.0-b23, mixed mode)
)
Hàm get của bạn có tham số được gọi là "sharedLock" nhưng bạn sử dụng thành viên có tên "lock" ("sharedLock" không được sử dụng). Điều này có chủ ý không? – Arne
Đây là điểm tôi bị hoang tưởng. Ngoài việc ghi nhật ký foo cuối cùng trước khi nhả khóa, hãy đăng nhập map.get ("key") và mã băm nhận dạng cho bản đồ. Khi đọc nhanh, chắc chắn mọi thứ đều ok và trên thực tế, khóa phải đủ nếu bản đồ không bị sửa đổi ở nơi khác. Có lẽ có điều gì đó quan trọng đã không làm cho nó thông qua việc tước bỏ câu hỏi? –
PSpeed
@Arne: không, chỉ là lỗi đánh máy. Sẽ sửa chữa. –