此问题与我已发布的以下问题一起
Preventing thread from duplicate processing in java
问题陈述:如何控制许多子线程之间共享的某些代码块只能访问一次。
场景:
现在,我有一个场景,多个线程共享一个缓冲区资源(一个普通的并发列表),它用一些值更新列表并在最后清除它。但是我希望这个操作能够在原子性的情况下执行。只有在第一个线程更新并清除列表后,第二个线程才应开始更新列表。如果操作不同步而第一个线程作业没有完成,那么可能会导致数据问题。
代码片段如下,我试图在线程中放置一个synchronized块。这有意义吗?它会起作用吗?同步块内的行应该一次只能被一个线程访问,而块本身就是一个新生成的线程。
public void processControlMessage(final Message message) {
try {
lock.lock();
RDPWorkflowControlMessage rdpWorkflowControlMessage = unmarshallControlMessage(message);
if (rdpWorkflowControlMessage != null) {
final String workflowName = rdpWorkflowControlMessage.getWorkflowName();
final RdpWorkflowControlMessageType controlMessageType = rdpWorkflowControlMessage.getControlMessage();
new Thread(new Runnable() {
@Override
public void run() {
try {
if (message instanceof TextMessage) {
if (controlMessageType != null && controlMessageType == RdpWorkflowControlMessageType.REFRESH) {
if (!isWorkflowBeingProcessed(workflowName)) {
log.info("Processing workflow control message for the workflow " + workflowName);
addShutdownHook(workflowName);
List<String> matchingValues = new ArrayList<String>();
matchingValues.add(workflowName);
ConcreteSetDAO tasksSetDAO = taskEventListener.getConcreteSetDAO();
ConcreteSetDAO workflowSetDAO = workflowEventListener.getConcreteSetDAO();
tasksSetDAO.deleteMatchingRecords(matchingValues);
workflowSetDAO.deleteMatchingRecords(matchingValues);
List<RDPWorkflowTask> allTasks = fetchNewWorkflowItems(workflowName);
//Will the below line be accessed and executed only by one thread??
updateAndClearTasksandWorkflowSet(allTasks);
removeWorkflowNameFromProcessingMap(workflowName);
} else {
log.info("RDA cache clean up is already in progress for the workflow " + workflowName);
}
}
}
} catch (Exception e) {
log.error("Error extracting item of type RDPWorkflowControlMessage from message " + message);
}
}
}).start();
}
} finally {
lock.unlock();
}
}
private boolean isWorkflowBeingProcessed(final String workflowName) {
if (controlMessageStateMap.get(workflowName) == null) {
synchronized (this) {
if (controlMessageStateMap.get(workflowName) == null) {
log.info("Adding an entry in to the processing map for the workflow " + workflowName);
controlMessageStateMap.put(workflowName, true);
return false;
}
}
}
return true;
}
private void addShutdownHook(final String workflowName) {
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
removeWorkflowNameFromProcessingMap(workflowName);
}
});
log.info("Shut Down Hook attached for the thread processing the workflow " + workflowName);
}
private RDPWorkflowControlMessage unmarshallControlMessage(Message message) {
RDPWorkflowControlMessage rdpWorkflowControlMessage = null;
try {
TextMessage textMessage = (TextMessage) message;
rdpWorkflowControlMessage = marshaller.unmarshalItem(textMessage.getText(), RDPWorkflowControlMessage.class);
} catch (Exception e) {
log.error("Error extracting item of type RDPWorkflowTask from message " + message);
}
return rdpWorkflowControlMessage;
}
private List<RDPWorkflowTask> fetchNewWorkflowItems(String workflowName) {
workflowRestServiceClient.initSSL();
List<RDPWorkflowTask> allTasks = workflowRestServiceClient.fetchWorkflowSpecificTasks(workflowName);
return allTasks;
}
private void updateAndClearTasksandWorkflowSet(List<RDPWorkflowTask> allTasks) {
synchronized (this) {
if (allTasks != null && allTasks.size() > 0) {
taskEventListener.addRDPWorkflowTasks(allTasks);
workflowEventListener.updateWorkflowStatus(allTasks);
taskEventListener.getRecordsForUpdate().clear();
workflowEventListener.getRecordsForUpdate().clear();
}
}
}
private synchronized void removeWorkflowNameFromProcessingMap(String workflowName) {
if (workflowName != null
&& (controlMessageStateMap.get(workflowName) != null && controlMessageStateMap.get(workflowName))) {
controlMessageStateMap.remove(workflowName);
log.info("Thread processing the " + workflowName + " is released from the status map");
}
}
答案 0 :(得分:0)
我认为你这是错误的做法。在processControlMessage()方法中,您将多次锁定和释放事物。您在某些情况下锁定实例,而在其他情况下,您正在同步方法。没有办法知道这些锁和版本之间发生了什么。
我相信您提交的内容,您正在尝试确保一次只有一个线程访问controlMessageStateMap。如果这是正确的,那么为什么不在块的开头锁定Map并在完成后释放它?
new Thread(new Runnable() {
@Override
public void run() {
try {
synchronize(controlMessageStateMap) {
if (message instanceof TextMessage) {
if (controlMessageType != null && controlMessageType == RdpWorkflowControlMessageType.REFRESH) {
if (!isWorkflowBeingProcessed(workflowName)) {
...
} // end of synchronize block
} catch (Exception e) {
log.error("Error extracting item of type RDPWorkflowControlMessage from message " + message);
}
我认为这不是一个很好的策略。但是如果不了解你想要做的事情的背景,我就不能建议另一种选择。
什么是原子性保护?你试图解决的用例是什么?