按其特殊顺序执行长时间线程



在应用程序中创建了许多耗时的线程(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) {
                }
            }
        }
    }
}

不会通过Executors.newSingleThreadExecutor()创建的Executor完全满足您的要求?"任务保证按顺序执行,并且在任何给定时间内活动的任务不超过一个。"

当您不需要并发执行作业时,不要创建新的Thread实例。即使您正在使用在Thread类中实现了一些逻辑的遗留代码,您也应该能够将它们作为Runnable实例执行给执行器。

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

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

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

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

实际上,您确实应该考虑使用Executor。我想你不会觉得很重的:

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

总是避免重写已经存在的东西。您将避免编写新的bug。例如,您的实现不是线程安全的。2同时调用addToThreadList会暴露一个非法的threadstateexception。

代码不错,但executor .newFixedThreadPool(nThreads)也不错。如果线程在任务池中进行长时间工作(500-900ms),则不会影响性能。JIT和其他JVM运行时优化可以更好地处理标准类。

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

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

ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.submit(new Runnable(){
    @Override
    public void run(){
        doSomethingThatTakesALongTime();
    }
});
executorService.submit(new Runnable(){
    @Override
    public void run(){
        doSomethingElseThatAlsoTakesALongTime();
    }
});
并发并不容易,所以我建议你利用Sun Oracle有专职的专家为你编写和维护这些库。这意味着有更多的空闲时间可以花在酒吧,与你的家人,或者为你的客户实现新的功能。

最新更新