如何在Java中创建一个线程池,在每次运行时创建一个新线程?

时间:2013-08-14 17:22:50

标签: java multithreading threadpool

这是我的情况:我正在研究一些单线程代码。代码是随机的,我需要运行它的许多实例来了解平均值。为了让生活更轻松,更快,我目前的解决方案是使用Executors.newFixedThreadPool。现在,问题是每个线程都需要拥有自己的独立数据。我最初实现它的方式是这样的:

public class Data {
    private static Map<Thread, Data> instanceMap = new ConcurrentHashMap<Thread, Data>();

    public static Data getInstance() {
        if (!instanceMap.containsKey(Thread.currentThread()))
            instanceMap.put(Thread.currentThread(), new Data());
        return instanceMap.get(Thread.currentThread());
    }

    private Data() {
    }
}

当迭代次数<=线程数时,这很好。但是,当我使用8个线程运行20次迭代时,就会出现问题。因为将重复使用这8个线程来运行这20个迭代,instanceMap将只包含8个实例。

那么正确处理这样的事情的方法是什么?我真正需要的是一个线程池,它可以在每次迭代后终止线程。有没有办法杀死runRunnable ExecutorService.submit对象的newFixedThreadPool方法中的线程?我应该考虑使用{{1}}的替代方案吗?

2 个答案:

答案 0 :(得分:4)

主要问题是您正在存储全局地图中某个线程执行的任务的本地数据。只需将数据范围扩展到任务,一切都会更简单:

Callable<Foo> task = new Callable<Foo>() {
    private Data data = new Data();

    public Foo call() {
        // execute your task here, using the task's data
    }
});

executorService.submit(task);

答案 1 :(得分:1)

JB Nizet的答案很好,但考虑到你拥有的,另一种方法可能是将你现有的Runnable包裹在另一个RunnableCallable内,这会删除Data个对象原始Runnable运行后:

class DataRunnable implements Runnable {
    private final Runnable child;

    DataRunnable(Runnable aChild) { child = aChild; }

    @Override
    public void run() {
        child.run();
        Data.removeOldDataForThisThread();
    }
}

让我补充一点,使用Data.getInstance()对象来保存实例可以简化您的ThreadLocal方法:

public class Data {
    private static ThreadLocal<Data> datas = new ThreadLocal<Data>() {
        @Override
        protected Data initialValue() { return new Data(); }
    };

    public static Data getInstance() {
        return datas.get();
    }

    public static void removeOldDataForThisThread() { datas.remove(); }

    private Data() {
    }
}