我有一个春天@RestController
,因此是一个简单的servlet
。
如果同时使用相同的值(在本例中命名为“hash”)调用servlet,我想阻止除第一个servlet之外的所有值。当这个结束时,我想释放被阻止的那些。
作为一种解决方案,我考虑将哈希添加到ConcurrentHashMap
,并将servlet线程添加到该哈希映射中作为哈希键的值。
但是我怎么能在那里添加一个正在运行的java线程呢?
以下伪代码说明了我要实现的目标:
@RestController
public class MyService {
//a map blocking any concurrent process on the same hash value
private ConcurrentHashMap<String, List<Object>> map;
@RequestMethod
public String myXmlMethod(Param params) {
String hash = params.getHash(); ////assume a value identifying a certain form of logic
if (!map.contains(hash)) {
//here no concurrent task is running, so block the hash until removal
map.put(hash, new ArrayList<Object>());
callLongRunningTaskAndWriteToDB();
List<Object> threads = map.get(hash);
map.remove(hash); //free the hash
//interrupt any waiting threads, as the hash completed now
if (threads != null && !threads.isEmpty()) {
for (thread : threads) {
thread.interruptWait();
}
}
} else {
//this way the servlet thread cannot continue until the timout occurs,
//or the servlet thread is canceled by the main thread in the concurrent hashmap
thread = new Thread(this, Timeout.SECONDS(30));
map.get(hash).add(thread);
waitForThreadTimeoutOrInterrupt();
}
}
}
问题:但是我怎样才能真正掌握方法当前正在执行的“线程”呢?这样我就可以将它添加到Map中,然后等待并打断它?
答案 0 :(得分:1)
答案 1 :(得分:1)
如果这是您的问题,您可以将当前帖子作为Thread.currentThread
进行访问,但我发现您正在尝试为callLongRunningTaskAndWriteToDB()
实现一种互斥,因此只有一个线程会执行码。
使用像java.util.concurrent.Semaphore
这样的基于Java的机制会不会更好?更重要的是,您可以在Runnable任务中设置callLongRunningTaskAndWriteToDB
方法并通过单例访问它,并确保只有一个线程执行该方法...
答案 2 :(得分:1)
您可以使用ConcurrentMap
FutureTask
执行此操作,如下所示:
我们首先定义ConcurrentMap
:
private final ConcurrentMap<String, FutureTask<MyResult>> map = new ConcurrentHashMap<>();
我们实现了阻止2个线程同时执行相同任务的逻辑:
@RequestMethod
public String myXmlMethod(Param params) {
String hash = params.getHash(); ////assume a value identifying a certain form of logic
FutureTask<MyResult> task = new FutureTask<>(new Callable<MyResult>() {
@Override
public MyResult call() throws Exception {
// My task here
}
});
// This boolean means we are the first to insert the entry
boolean inserted = true;
try {
FutureTask<MyResult> previous = map.putIfAbsent(hash, task);
if (previous == null) {
// The task has not been defined so far so we execute it
task.run();
} else {
// the task has already been defined
task = previous;
inserted = false;
}
// we wait until we get the result
return task.get();
} finally {
// Clean up the per key map but only if our insertion succeeded and with our future
if (inserted) {
map.remove(hash, task);
}
}
}