Первая причина, которую я вижу, здесь
Object lock = null;
lock = locks.get(shortcode);
if (lock == null)
{
locks.put(shortcode, lock = new Object());
}
Этот блок кода выполняется вне любого мьютекса, поэтому несколько потоков могут запускать его одновременно, поэтому каждый из потоков (имеющих одинаковый шорткод) получил свою собственную блокировку , независимую друг от друга (и только один из них будет храниться в hashmap блокировок - о чем и идет речь, поскольку обычный HashMap не предназначен для одновременного использования - вы не можете предсказать, какой именно «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 + " ......");
}
}
Таким образом, вы получаете ровно одну блокировку для каждого шорткода. Более эффективный способ - использовать что-то вроде ComputableConcurrentHashMap из библиотеки Guava.