如何阻止和取消阻塞servlet线程?

时间:2016-04-21 15:00:12

标签: java spring multithreading servlets

我有一个春天@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中,然后等待并打断它?

3 个答案:

答案 0 :(得分:1)

如果您的问题只是如何获取当前线程,则可以使用类Thread的静态方法currentThread获取当前线程。

来自javadoc

  

返回对当前正在执行的线程对象的引用。

答案 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);
        }
    }
}