Java 还有什么更高效的“在规定时间内执行某个方法”的办法吗?

红薯 发布于 2017/12/12 13:28
阅读 1K+
收藏 3

使用 ExecutorService 进行调度的话,调度本身耗时挺高,如下面代码:

任务本身没有任何延迟,这样的代码执行耗时 50 毫秒以上(Mac Pro 机器,i7处理器)

public class TaskExecutor {

    /**
     * 在指定毫秒内完成某个任务并返回结果
     * @param task
     * @param millSeconds
     * @return
     */
    public static Object execute(Callable<Object> task, int millSeconds) {
        Object result = null;
        ExecutorService threadPool = Executors.newFixedThreadPool(1);
        try {
            Future<Object> future = threadPool.submit(task);
            result = future.get(millSeconds, TimeUnit.MILLISECONDS);
        } catch (InterruptedException | TimeoutException e) {
        } catch (ExecutionException e) {
            throw new RuntimeException(e.getCause());
        } finally  {
            threadPool.shutdownNow();
        }
        return result;
    }

    /**
     * 测试
     * @param args
     */
    public static void main(String[] args) {
        long ct = System.currentTimeMillis();
        System.out.println(execute(()->{
            //Thread.sleep(400);
            return "hello";
        }, 1000));
        System.out.printf("Execute time :%d ms\n", (System.currentTimeMillis() - ct));
    }

}

这 50 毫秒的耗时没法接受啊,还有什么其他方法更高效吗?

加载中
1
乌龟壳
乌龟壳

首先,要实现任意任务的超时,只能用线程。比较高效的办法就是用线程池去重用它。

需要预先分配一定数量的工作线程(不要在execute里分配,同时也不要在execute里shutdown那些)。就像你的逻辑,每次把任务提交给线程池,然后用future实现超时。

这里有个细节,交给线程池实现的线程最好实现如下接口。

interface task extends Callable<Object> {
    public void terminate();
}

让execute函数在超时后调用terminate函数终止运行。具体terminate的实现可根据Callable的功能自定义处理。比如如果是计算密集的,那就写一个volatile标记,如果是网络通信的,直接close相关socket让它报错。

1
乌龟壳
乌龟壳

每次都要新建线程池是什么意思?

一只小桃子
一只小桃子
红薯钓鱼帖
1
talent-tan
talent-tan
package org.tio.core.ssl;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class TaskExecutor2 {

	public TaskExecutor2() {
		// TODO Auto-generated constructor stub
	}
	static ExecutorService threadPool = Executors.newFixedThreadPool(1);
	 /**
     * 在指定毫秒内完成某个任务并返回结果
     * @param task
     * @param millSeconds
     * @return
     */
    public static Object execute(Callable<Object> task, int millSeconds) {
        Object result = null;
        
        try {
            Future<Object> future = threadPool.submit(task);
            result = future.get(millSeconds, TimeUnit.MILLISECONDS);
        } catch (InterruptedException | TimeoutException e) {
        } catch (ExecutionException e) {
            throw new RuntimeException(e.getCause());
        } finally  {
            //threadPool.shutdownNow();
        }
        return result;
    }

    /**
     * 测试
     * @param args
     */
    public static void main(String[] args) {
        for(int i = 0; i <100; i++) {
        	test();
        }
    }
    
    public static void test() {
        long ct = System.currentTimeMillis();
        System.out.println(execute(()->{
            //Thread.sleep(400);
            return "hello";
        }, 1000));
        System.out.printf("Execute time :%d ms\n", (System.currentTimeMillis() - ct));
    }
}

 

 

这样写,除了第一次要50ms外,其它都是0秒

1
OutMan/pch
OutMan/pch
先创建连接池
1
_凤求凰_
_凤求凰_
应该把线程池提炼出来当类变量。不要每次调用方法就创建线程。
0
依然菜刀
依然菜刀

楼上被我点赞的说的对。

talent-tan
talent-tan
哈哈,那要不要来给t-io投一票呢?
0
A_NOOB
A_NOOB
rxjava 被观察者注册观察者模式可以试试
0
小木头的冬天
小木头的冬天

尝试下 CompletableFuture 这个呢

返回顶部
顶部