以特殊顺序执行长时间线程

时间:2011-08-31 16:03:28

标签: java multithreading

在应用程序中创建了许多耗时的线程(500-900ms。)。 它们将按照它们被创建的顺序执行 - 一个接一个 - 而不是同时执行。执行应该在线程中处理,与主应用程序线程不同步。

我无法按顺序执行小线程,所以我找到了一个ThreadPoolExecutor,但认为它对我的任务来说太重了。所以我写了我的Executor课程。

工作正常。您向threadList添加一个线程,它启动Executor线程来执行可以在执行时添加的小任务。

你能告诉我它的缺点吗?也许是解决我问题的另一种更好的方法。

import java.util.LinkedList;
import java.util.List;

public class SfourExecutor extends Thread implements Runnable {

    private static List <Thread> threadList = new LinkedList<Thread>();
    private static final SfourExecutor INSTANCE = new SfourExecutor();

    public static List<Thread> getThreadList() {
        return threadList;
    }

    public static void setThreadList(List<Thread> threadList) {
        SfourExecutor.threadList = threadList;
    }

    public void addToThreadList(Thread thread) {
        getThreadList().add(thread);
        if (!this.isAlive()) {
            this.start();
        }
    }

    public static SfourExecutor getInstance() {
        return SfourExecutor.INSTANCE;
    }

    private static class SfourHolder {
        private static final SfourExecutor INSTANCE = new SfourExecutor();
    }

    SfourExecutor () {
    }


    @Override
    public void run() {
        LinkedList <Thread> tL = (LinkedList<Thread>) getThreadList();

        while (!tL.isEmpty()) {
            Thread t = tL.poll();
            if (t!=null) {
                t.start();
                try {
                    t.join();
                } catch (InterruptedException ex) {
                }
            }
        }
    }

}

5 个答案:

答案 0 :(得分:4)

通过Executors.newSingleThreadExecutor()创建的Executor不会完全满足您的要求吗? “任务保证按顺序执行,任何给定时间都不会有多于一个任务。”

当您不需要同时执行作业时,请不要创建新的Thread实例。即使您正在使用已在Thread类中实现某些逻辑的遗留代码,您也应该execute将它们作为执行者的Runnable个实例。

如果您坚持使用自己的执行程序,则应该知道当前的实现不是线程安全的。 LinkedList不是并发数据结构,并且由于进程中的任何代码都可以随时添加新作业,因此您无法确保在执行程序线程启动之前将所有作业添加到列表中。因此,不保证对使用它的所有线程都可以看到对列表的更改。

答案 1 :(得分:2)

为什么使用线程而不是Runnables?有一个Runnables列表并在它们上面调用run()而不是一个线程列表并等待每个线程结束是不是更容易?

除此之外,您的解决方案似乎还不错。

在这两种情况下,我只会在addToThreadList和块周围添加某种形式的同步,以检查是否有任务要在run()方法中执行,因为这两段代码有可能在同一时间在同一链表上,不同步。

答案 2 :(得分:2)

实际上,你应该考虑使用Executor。我认为你不会发现它很重:

int maxThreads = 1;
ExecutorService myService = Executors.newFixedThreadPool(maxThreads);
...
myService.execute(myRunnable);

始终避免重写已存在的内容。你将避免编写新的bug。例如,您的实现不是线程安全的。同时调用addToThreadList会同时暴露一个illegalthreadstateexception。

答案 3 :(得分:1)

很好的代码,但Executors .newFixedThreadPool(nThreads)也很好。如果您的线程在您的任务中长时间工作(500-900ms) - 池开销不会影响性能。 JIT和另一个JVM运行时优化可以更好地与标准类一起使用。

答案 4 :(得分:1)

您遇到的问题是,一旦线程列表为空,您的处理线程将停止检查添加到列表中的新线程。此外,LinkedList对于并发使用是不安全的,因此执行程序线程可能看不到一个线程提交的内容(或者更糟糕的是,它可能不会以您提交它的方式显示)。如果您使用了LinkedBlockingQueue,它会更好用。

但是,由于您希望所有内容按顺序运行,因此您无需创建和启动大量新线程(这非常昂贵),您可以只使用一个运行轻量级Runnable任务的线程订购。 ThreadPoolExecutor为您做了这个,以及更多,如果您从Executors类(在幕后使用ThreadPoolExecutor)获得帮助,它也非常容易使用:

ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.submit(new Runnable(){
    @Override
    public void run(){
        doSomethingThatTakesALongTime();
    }
});
executorService.submit(new Runnable(){
    @Override
    public void run(){
        doSomethingElseThatAlsoTakesALongTime();
    }
});

并发并不容易,因此我建议您利用 Sun Oracle的事实,让专职人员全职为您编写和维护这些库。这意味着可以获得更多的空闲时间,您可以在酒吧,家人或为客户实施新功能。