我创建了一个类,它尝试在多个线程中处理一些消息,其中每个消息都属于一个特定的组。每条消息都被添加到ConcurrentHashMap中,其中有一个密钥作为组号,并在这些线程处于“处理”状态时填满。我注意到它们有时并行运行,有时不运行。更糟糕的是,当有超过2个进程线程运行时,它们总是完全死锁。
[EDIT]
ConcurrentHashMap
的迭代在当时似乎是一种通过所有元素的好方法,因为编号的消息组(键)是未知的,并且它可能随时间而变化。该任务指定将所有消息组合在一起进行处理,但是当组中只有一条消息时,它仍应处理。所以我认为这是一种在元素到达时对元素进行排序的方法,而不知道哪些组存在。
[\EDIT]
public class GroupPriorityProcess implements Runnable {
private static final Object lock = new Object();
private static final Object counterLock = new Object();
private static int threadCounter = 0;
private final int currentThreadNumber;
private static Iterator<Integer> groupIterator;
private ConcurrentHashMap<Integer, LinkedBlockingQueue<Message>> groupMsgQueues;
public GroupPriorityProcess(ConcurrentHashMap<Integer, LinkedBlockingQueue<Message>> groupedMsgQueues) {
groupMsgQueues = groupedMsgQueues;
synchronized(lock){
if (groupIterator == null)
groupIterator = groupedMsgQueues.keySet().iterator();
}
synchronized (counterLock) {
currentThreadNumber = (threadCounter++);
}
}
// Main while loop for threads to process messages
public void run() {
while (true) {
LinkedBlockingQueue<Message> queue = chooseGroup();
synchronized (queue) {
process(queue);
}
}
}
// Loops till finds a message group available for processing.
private LinkedBlockingQueue<Message> chooseGroup() {
synchronized (lock) {
while (!groupIterator.hasNext()) {
groupIterator = groupMsgQueues.keySet().iterator();
}
LinkedBlockingQueue<Message> queue = groupMsgQueues.get(groupIterator.next());
return queue;
}
}
// takes messages from the a particular message group queue to completes the
// send process
private void process(LinkedBlockingQueue<Message> queue) {
try {
while (!queue.isEmpty()) {
Message msg = queue.take();
msg.appendMessage("Thread: " + currentThreadNumber);
msg.completed();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
[EDIT]
这些消息将添加到另一个类GatewayImp
中。
public void send(Message msg) {
int groupID = msg.getGroupID();
if (groupedMsgQueues.containsKey(groupID)) {
LinkedBlockingQueue<Message> queue = groupedMsgQueues.get(groupID);
queue.add(msg);
} else {
LinkedBlockingQueue<Message> queue = new LinkedBlockingQueue<Message>();
try {
queue.put(msg);
} catch (InterruptedException e) {
e.printStackTrace();
}
groupedMsgQueues.put(groupID, queue);
}
}
}
我有几次使用'check then act',我认为需要在同步块中制作原子,但我想知道有更好的方法。非常感谢任何帮助,因为我只是刚开始学习并发性,而且我发现很难特别关注锁定。
答案 0 :(得分:0)
我的第一个猜测是你不应该在queue
方法的run
上进行同步。
如果您稍后在LinkedBlockingQueue
方法中调用queue.take()
(同时仍保留process
的互斥锁),则可能会与queue
的内部同步发生冲突。
为了帮助您调试代码,添加详细日志记录(例如,一些System.out.println
语句)通常很有用。好消息是你似乎有办法重现死锁。通常,这说起来容易做起来......