首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在java中运行带超时的异步代码

在java中运行带超时的异步代码
EN

Stack Overflow用户
提问于 2015-01-23 18:39:02
回答 2查看 4.8K关注 0票数 2

在我编写的web服务器中,每个请求都会调用一个操作列表。其中一些操作并不像其他操作那样关键,所以我想在后台线程中运行它们。

此外,由于它们不是那么重要,我不关心它们中的一个是否会罕见地失败,我也不希望它们永远占用一个线程,所以其他线程将可用于处理下一批处理。

因此,我希望有一个线程池(例如: 10个线程),并像这样向每个后台任务分发一个线程。将每个线程限制在1秒内,如果在此时间内它还没有完成,就干掉它,并为下一个任务做好准备。

我该怎么做呢?

到目前为止,我得到的是:

代码语言:javascript
复制
public class AsyncCodeRunner {

    private static final ExecutorService executor = Executors.newFixedThreadPool(10);

    public void Run(Callable<Void> callableCode, int timeout) {

        final int threadTimeout = 10;
        Future<Void> callableFuture = executor.submit(callableCode);

        try {
            callableFuture.get(threadTimeout, TimeUnit.SECONDS);
        } catch (Exception e) {
            logger.Info("Thread was timed out", e);
        }
    }
}

我想像这样使用这个类:

代码语言:javascript
复制
public void processRequest(RequestObject request) {

    // do some important processing

    // throw some less important processing to background thread
    (new AsyncCodeRunner()).Run(new Callable<Void> () {
        @Override
        public Void call() throws Exception {
            // do something...
            return null;
        }
    }, 1); // 1 second timeout

    // return result (without waiting for background task)
    return;

}

这会像我想要的那样工作吗?或者,我应该如何更改它,使其有效?

如果我调用了Run(),但是线程池中没有可用的线程可供分配,会发生什么呢?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-01-23 18:51:23

我认为你这个相当优雅的想法的主要问题是,你只是在Futureget上超时,一旦它超时,你实际上不会中止进程,你只是放弃等待它。当你意识到你甚至可能在进程还没有启动的时候就超时了,这个问题就变得更加复杂了--它只是在队列中。

也许像这样的东西会很有效。它确实需要两个线程,但一个TimerTask线程应该消耗很少。

代码语言:javascript
复制
public class RunWithTimeout {

    public RunWithTimeout(Runnable r, long timeout) {
        // Prepare the thread.
        final Thread t = new Thread(r);
        // Start the timer.
        new Timer(true).schedule(new TimerTask() {

            @Override
            public void run() {
                if (t.isAlive()) {
                    // Abort the thread.
                    t.interrupt();
                }
            }
        }, timeout * 1000);
        // Start the thread.
        t.start();
    }

}

class WaitAFewSeconds implements Runnable {

    final long seconds;

    WaitAFewSeconds(long seconds) {
        this.seconds = seconds;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(seconds * 1000);
        } catch (InterruptedException ie) {
            System.out.println("WaitAFewSeconds(" + seconds + ") - Interrupted!");
        }
    }

}

public void test() {
    new RunWithTimeout(new WaitAFewSeconds(5), 3);
    new RunWithTimeout(new WaitAFewSeconds(3), 5);
}

这里有一个替代方案,只使用一个额外的线程。

代码语言:javascript
复制
public class ThreadKiller implements Runnable {

    DelayQueue<WaitForDeath> kill = new DelayQueue<>();

    private class WaitForDeath implements Delayed {

        final Thread t;
        final long finish;

        public WaitForDeath(Thread t, long wait) {
            this.t = t;
            this.finish = System.currentTimeMillis() + wait;
        }

        @Override
        public long getDelay(TimeUnit unit) {
            return unit.convert(finish - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
        }

        @Override
        public int compareTo(Delayed o) {
            long itsFinish = ((WaitForDeath) o).finish;
            return finish < itsFinish ? -1 : finish == itsFinish ? 0 : 1;
        }

    }

    @Override
    public void run() {
        while (true) {
            try {
                WaitForDeath t = kill.take();
                if (t.t.isAlive()) {
                    // Interrupt it.
                    t.t.interrupt();
                }
            } catch (InterruptedException ex) {
                // Not sure what to do here.
            }
        }
    }

    public void registerThread(Thread t, long wait) {
        // Post it into the delay queue.
        kill.add(new WaitForDeath(t, wait));
    }
}

public void test() throws InterruptedException {
    // Testing the ThreadKiller.
    ThreadKiller killer = new ThreadKiller();
    Thread killerThread = new Thread(killer);
    killerThread.setDaemon(true);
    Thread twoSeconds = new Thread(new WaitAFewSeconds(2));
    Thread fourSeconds = new Thread(new WaitAFewSeconds(4));
    killer.registerThread(twoSeconds, 5000);
    killer.registerThread(fourSeconds, 3000);
    killerThread.start();
    twoSeconds.start();
    fourSeconds.start();
    System.out.println("Waiting");
    Thread.sleep(10 * 1000);
    System.out.println("Finished");
    killerThread.interrupt();
}
票数 2
EN

Stack Overflow用户

发布于 2019-03-06 20:56:07

当线程运行时,你需要启动计时器。那么处于等待状态的线程都不会被杀死。以下是来自this thread的示例

代码语言:javascript
复制
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class PoolTest {
    class TimeOutTask extends TimerTask {
        Thread t;

        TimeOutTask(Thread t) {
            this.t = t;
        }

        public void run() {
            if (t != null && t.isAlive()) {
                t.interrupt();
            }
        }
    }

    class MyRunnable implements Runnable {
        Timer timer = new Timer(true);

        public void run() {
            timer.schedule(new TimeOutTask(Thread.currentThread()), 1000);
            try {
                System.out.println("MyRunnable...");
                Thread.sleep(10000);
            } catch (InterruptedException ie) {
                System.out.println("MyRunnable error...");
                ie.printStackTrace();
            }
        }
    }

    public static void main(String args[]) {
        new PoolTest();
    }

    public PoolTest() {
        try {
            ExecutorService pe = Executors.newFixedThreadPool(3);
            pe.execute(new MyRunnable());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28108022

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档