繁体   English   中英

如何阻止和解除阻止servlet线程?

[英]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获取当前线程。

javadoc

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

如果这是您的问题,则可以以Thread.currentThread访问当前线程,但是我看到您正在尝试为callLongRunningTaskAndWriteToDB()实现一种互斥,因此只有一个线程将执行该代码。

使用像java.util.concurrent.Semaphore这样的基于Java的机制会更好吗? 甚至可以在Runnable任务中设置callLongRunningTaskAndWriteToDB方法,并通过单例访问该方法,并确保只有一个线程执行该方法...

您可以使用FutureTaskConcurrentMap做到这一点,如下所示:

我们首先定义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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM