0

我正在开发一个聊天应用程序。我有一个处理聊天消息的功能。每个聊天室都由唯一的简码标识。现在我希望当一个简码的消息正在处理时,同一简码的另一条消息应该等待,而其他简码的消息应该继续。

请考虑遵循代码的和平,它有什么问题,因为相同短代码的消息正在并行处理。我只是猜不出问题

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 + " ......");
    }
}
4

2 回答 2

4

我能看到的第一个原因就在这里

Object lock = null;

lock = locks.get(shortcode);
if (lock == null)
{
    locks.put(shortcode, lock = new Object());
}

该代码块在任何互斥体之外执行,因此多个线程可以同时运行它,因此每个线程(具有相同的短代码)都有自己的 lock,彼此独立(并且只有一个线程将存储在 locks hashmap 中-- 这是哪一个问题,因为普通的 HashMap 不是为并发使用而设计的 -- 您无法准确预测哪个“放置”实际上会以哪个顺序生效,您甚至可以在此代码中遇到异常或错误行为,如果当前例如将导致调整大小)。由于每个线程都有自己的锁,因此它不会阻止它与其他线程同时获取它,从而获得另一个锁。

最简单(但不是很有效)的修复方法:

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 之类的东西。

于 2011-09-02T08:40:06.303 回答
1

同步机制很好,但也许你想看看 java.util.concurrent.locks 包中的 Lock 接口。这些使用起来更冗长,但允许更大的灵活性,因为可以执行诸如尝试和失败之类的操作,或者尝试超时获取。

于 2011-09-02T09:05:38.893 回答