在应用程序中创建了许多耗时的线程(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) {
}
}
}
}
}
答案 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的事实,让专职人员全职为您编写和维护这些库。这意味着您可以获得更多的空闲时间,您可以在酒吧,家人或为客户实施新功能。