2010-07-20 40 views
21

Chúng tôi đã gặp một vấn đề lạ với ConcurrentHashMap, trong đó hai chủ đề dường như đang gọi put() và sau đó chờ đợi mãi mãi bên trong phương thức Unsafe.park(). Từ bên ngoài, nó trông giống như một bế tắc bên trong ConcurrentHashMap.Có thể dùng ConcurrentHashMap để "bế tắc" không?

Chúng tôi chỉ thấy điều này xảy ra một lần cho đến thời điểm này.

Có ai có thể nghĩ ra bất cứ điều gì có thể gây ra các triệu chứng này không?

EDIT: Sợi chỉ đổ cho các chủ đề có liên quan là ở đây:

 

"[redacted] Thread 2" prio=10 tid=0x000000005bbbc800 nid=0x921 waiting on condition [0x0000000040e93000] 
    java.lang.Thread.State: WAITING (parking) 
    at sun.misc.Unsafe.park(Native Method) 
    - parking to wait for <0x00002aaaf1207b40> (a java.util.concurrent.locks.ReentrantLock$NonfairSync) 
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:158) 
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:747) 
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:778) 
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1114) 
    at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:186) 
    at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:262) 
    at java.util.concurrent.ConcurrentHashMap$Segment.put(ConcurrentHashMap.java:417) 
    at java.util.concurrent.ConcurrentHashMap.put(ConcurrentHashMap.java:883) 
    at [redacted] 


"[redacted] Thread 0" prio=10 tid=0x000000005bf38000 nid=0x91f waiting on condition [0x000000004151d000] 
    java.lang.Thread.State: WAITING (parking) 
    at sun.misc.Unsafe.park(Native Method) 
    - parking to wait for <0x00002aaaf1207b40> (a java.util.concurrent.locks.ReentrantLock$NonfairSync) 
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:158) 
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:747) 
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:778) 
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1114) 
    at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:186) 
    at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:262) 
    at java.util.concurrent.ConcurrentHashMap$Segment.put(ConcurrentHashMap.java:417) 
    at java.util.concurrent.ConcurrentHashMap.put(ConcurrentHashMap.java:883) 
    at [redacted] 
+6

Bạn có kết xuất chuỗi không? –

+0

@ John W .: điểm tốt. Tôi sẽ đăng nó ngay sau khi tôi có thể lấy nó ra khỏi máy chủ. –

+0

Có phần nào khác của kết xuất chuỗi chỉ ra chuỗi nào thực sự sở hữu khóa không? Những sợi chỉ đơn giản là chờ đợi để có được. Tìm hiểu những gì họ đang chờ đợi có thể giúp đỡ. –

Trả lời

4

Có lẽ không phải là câu trả lời mà bạn muốn, nhưng điều này có thể là một lỗi JVM. Xem

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6865591

+0

Lỗi liên quan này trông khá gần: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6822370. Chúng tôi sẽ cố gắng nâng cấp lên phiên bản Java 6 mới nhất, như được cho là lỗi sau được sửa. Cảm ơn bạn đã đăng bài này. –

4

Gói không an toàn là nguồn gốc, triển khai phụ thuộc vào nền tảng.

Ngắt kết thúc chuỗi thứ ba (trên nền tảng, ngoại lệ không phải là vấn đề). Việc mua khóa trên bản đồ có thể gây ra tình trạng như vậy - trạng thái khóa bị hỏng, hai chủ đề khác bị tắt và chờ ai đó gọi Unsafe. unpark() (Và điều đó sẽ không bao giờ xảy ra).

5

Tôi không nghĩ rằng đây là những gì đang xảy ra trong trường hợp của bạn, nhưng có thể viết một bế tắc với một trường hợp duy nhất là ConcurrentHashMap và chỉ cần một chuỗi! Giữ tôi bị mắc kẹt trong một thời gian.

Giả sử bạn đang sử dụng ConcurrentHashMap<String, Integer> để tính toán biểu đồ. Bạn có thể làm điều gì đó như sau:

int count = map.compute(key, (k, oldValue) -> { 
    return oldValue == null ? 1 : oldValue + 1; 
}); 

Chỉ hoạt động tốt.

Nhưng giả sử bạn quyết định thay vì để viết nó như thế này:

int count = map.compute(key, (k, oldValue) -> { 
    return map.putIfAbsent(k, 0) + 1; 
}); 

Bây giờ bạn sẽ nhận được một bế tắc 1 sợi với một chồng như thế này:

Thread [main] (Suspended) 
    owns: ConcurrentHashMap$ReservationNode<K,V> (id=25) 
    ConcurrentHashMap<K,V>.putVal(K, V, boolean) line: not available  
    ConcurrentHashMap<K,V>.putIfAbsent(K, V) line: not available  
    ConcurrentHashMapDeadlock.lambda$0(ConcurrentHashMap, String, Integer) line: 32 
    1613255205.apply(Object, Object) line: not available  
    ConcurrentHashMap<K,V>.compute(K, BiFunction<? super K,? super V,? extends V>) line: not available 

Trong ví dụ trên, thật dễ dàng để thấy rằng chúng tôi đang cố gắng sửa đổi bản đồ bên trong một sửa đổi nguyên tử, điều này có vẻ như là một ý tưởng tồi. Tuy nhiên, nếu có một trăm ngăn xếp sự kiện gọi lại giữa cuộc gọi đến map.computemap.putIfAbsent thì có thể rất khó để theo dõi.

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