想用 wait/notify 和 map 来实现一个线程写入,另一个线程随后读出的同步处理。
但是遇到了 happens-before 问题。
一个可以复现的代码如下:
import java.time.LocalDateTime;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MainConcurrentHashmapTest {
private static ExecutorService executorService = Executors.newFixedThreadPool(2);
public static void main(String[] args) {
for (int i = 0; i != 100000; ++i) {
test();
}
executorService.shutdown();
}
public static void test() {
final Map<String, Object> map = new ConcurrentHashMap<String, Object>();
final Object mutex = new Object();
final String key = UUID.randomUUID().toString();
Runnable consumer = new Runnable() {
@Override
public void run() {
synchronized (mutex) {
try {
mutex.wait(10000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
Object value = map.remove(key);
if (value == null) {
System.out.println("got null value for key = " + key);
}
}
}
};
Runnable producer = new Runnable() {
@Override
public void run() {
map.put(key, LocalDateTime.now().toString());
synchronized (mutex) {
mutex.notify();
}
}
};
executorService.submit(consumer);
executorService.submit(producer);
}
}
运行的时候会发现,有时候得不到最新的 value 值,如下:
got null value for key = f972a078-c314-4cd1-a5e4-d3ce11195a7e
got null value for key = 6ef9476c-8ded-43ec-900e-5f859eeaec1e
got null value for key = 8ecff482-eb9a-4e63-8eee-c950a485fbb0
为什么呢?有什么改进建议么?
1
chendy 2019-06-07 23:45:10 +08:00
线程池执行任务的顺序不一定是提交的顺序,consumer 的方法可能会在 producer 之前执行,所以会取到 null
|
2
momocraft 2019-06-07 23:51:13 +08:00
沒有東西保證 consumer 比 producer “隨後” 獲得鎖
工具就比較多了 比如 CountdownLatch |
3
springmarker 2019-06-08 00:22:26 +08:00
BlockingQueue 不就好了
|
4
mejee 2019-06-08 01:16:14 +08:00 via Android
楼上说的对,还有一个问题,根据代码,不停地 submit 这两个 runable,很可能在某一次执行中,producer 先 notify,这就导致 consumer 会 wait 10000 ms,造成程序卡顿。还有,你每次 test 方法运行,用的是不同的 mutex,根据前面的情况,这就可能导致两个 consumer 同时霸占两个线程,直到 wait 等待超时,造成程序卡顿,幸好你 wait 带了个时间参数,否则你运行这么多次的 test 方法,非常有可能这个线程池停在那,导致你程序一直不执行下去
|
5
NewDraw 2019-06-08 08:49:30 +08:00 via Android
你的需求是阻塞队列。
|
6
johnniang 2019-06-08 13:23:31 +08:00 via Android
建议先看懂#生产者消费者模型#。
|
7
dailiha01sy 2019-06-09 01:35:37 +08:00
用 Exchange
|