在应用程序中创建了许多耗时的线程(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();
}
});
并发并不容易,所以我建议你利用