我正在开发一个聊天应用程序。我有一个处理聊天消息的功能。每个聊天室都由唯一的短代码标识。现在我希望当正在处理一个短代码的消息时,应该等待同一短代码的另一条消息,而其他短代码的消息应该继续。
请考虑遵循代码的和平,它有什么问题,因为同一短代码的消息正在并行处理。我只是猜不出问题
private HashMap<String, Object> locks = new HashMap<String, Object>();
public void handleShortCode(String shortcode,String message,String from)
{
Object lock = null;
lock = locks.get(shortcode);
if (lock == null)
{
locks.put(shortcode, lock = new Object());
}
synchronized (lock)
{
System.out.println("Handling shortcode:" + shortcode);
// processing
System.out.println("Successfully handled shortcode:" + shortcode + " ......");
}
}
答案 0 :(得分:4)
我能看到的第一个原因就在这里
Object lock = null;
lock = locks.get(shortcode);
if (lock == null)
{
locks.put(shortcode, lock = new Object());
}
这个代码块在任何互斥锁之外执行,所以几个线程可以同时运行它,所以每个线程(具有相同的短代码)得到它自己的锁,彼此独立(和只有其中一个将存储在锁定hashmap中 - 这是一个问题,因为普通的HashMap不是为并发使用而设计的 - 你无法准确地预测哪个“put”将按照哪个顺序生效,你甚至可以得到此代码中的异常或错误行为,如果当前put导致调整大小,例如)。由于每个线程都获得了自己的锁,因此它不会阻止它与其他线程并发获取它,从而获得另一个锁。
最简单(但不是非常有效)的解决方法:
private HashMap<String, Object> locks = new HashMap<String, Object>();
private final Object hashmapLock = new Object();
public void handleShortCode(String shortcode,String message,String from)
{
Object lock = null;
synchronized(hashmapLock){
lock = locks.get(shortcode);
if (lock == null)
{
locks.put(shortcode, lock = new Object());
}
}
synchronized (lock)
{
System.out.println("Handling shortcode:" + shortcode);
// processing
System.out.println("Successfully handled shortcode:" + shortcode + " ......");
}
}
这样,每个短代码只能获得一个锁。更有效的方法是使用Guava lib中的ComputableConcurrentHashMap。
答案 1 :(得分:1)
同步机制很好,但是你可能想看看java.util.concurrent.locks包中的Lock接口。这些使用起来比较冗长,但允许更大的灵活性,因为它可以执行尝试和失败之类的操作,或尝试通过超时获取。