[英]How to block and unblock a servlet thread?
我有一个spring @RestController
,因此是一个简单的servlet
。
如果以相同的值并发调用servlet(在此示例中命名为“哈希”),那么我想阻止除第一个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();
}
}
}
问题:但是,实际上如何获得该方法当前正在执行的“线程”的句柄? 这样我就可以将其添加到地图中,然后等待并中断它?
如果这是您的问题,则可以以Thread.currentThread
访问当前线程,但是我看到您正在尝试为callLongRunningTaskAndWriteToDB()
实现一种互斥,因此只有一个线程将执行该代码。
使用像java.util.concurrent.Semaphore
这样的基于Java的机制会更好吗? 甚至可以在Runnable任务中设置callLongRunningTaskAndWriteToDB
方法,并通过单例访问该方法,并确保只有一个线程执行该方法...
您可以使用FutureTask
的ConcurrentMap
做到这一点,如下所示:
我们首先定义ConcurrentMap
:
private final ConcurrentMap<String, FutureTask<MyResult>> map = new ConcurrentHashMap<>();
我们实现了防止两个线程同时执行相同任务的逻辑:
@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);
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.