在我的Android项目中,我有很多地方需要异步运行一些代码(Web请求,调用db等)。这不是长时间运行的任务(最多几秒钟)。 到目前为止,我正在创建一个新线程,通过该任务传递一个新的runnable。但是最近我读了一篇关于Java中的线程和并发的文章,并且理解为每个任务创建一个新的Thread并不是一个好的决定。
所以现在我在我的ThreadPoolExecutor
类中创建了一个Application
,它拥有5个线程。
这是代码:
public class App extends Application {
private ThreadPoolExecutor mPool;
@Override
public void onCreate() {
super.onCreate();
mPool = (ThreadPoolExecutor)Executors.newFixedThreadPool(5);
}
}
我还有一种方法可以将Runnable任务提交给执行者:
public void submitRunnableTask(Runnable task){
if(!mPool.isShutdown() && mPool.getActiveCount() != mPool.getMaximumPoolSize()){
mPool.submit(task);
} else {
new Thread(task).start();
}
}
因此,当我想在我的代码中运行异步任务时,我得到App
的实例,并调用submitRunnableTask
方法将runnable传递给它。正如你所看到的,我也检查,如果线程池有自由线程来执行我的任务,如果没有,我创建一个新线程(我不认为这会发生,但无论如何......我不希望我的任务在队列中等待并放慢应用程序的速度。)
在Application的onTerminate
回调方法中,我关闭了池。
所以我的问题如下:这种模式是否比在代码中创建新线程更好?我的新方法有哪些优点和缺点?它会引起我不知道的问题吗?你能告诉我一些比这更好的东西来管理我的异步任务吗?
P.S。我在Android和Java方面有一些经验,但我远不是一个并发大师。所以可能有些方面我不太了解这类问题。任何建议将不胜感激。
答案 0 :(得分:20)
此答案假定您的任务很短
这种模式比代码中创建新线程更好吗?
它更好,但它仍然远非理想。您仍在为短任务创建线程。相反,您只需要创建一个不同类型的线程池 - 例如Executors.newScheduledThreadPool(int corePoolSize)
。
行为的差异是什么?
FixedThreadPool
将始终具有一组要使用的线程,如果所有线程都忙,则新任务将被放入队列中。 ScheduledThreadPool
类创建的A(默认)Executors
具有最小线程池,即使在空闲时也会保留该线程池。如果新任务进入时所有线程都忙,它会为它创建一个新线程,并在完成后60秒处理该线程,除非再次需要它。第二个允许您不自己创建新线程。这种行为可以在没有"预定"部分,但你必须自己构建执行程序。
是构造函数public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue)
各种选项可让您微调行为。
如果某些任务很长......
我的意思很长。与大多数应用程序生命周期一样(实时双向连接?服务器端口?多播侦听器?)。在这种情况下,将Runnable
放入执行程序是有害的 - 标准执行程序不旨在应对它,并且它们的性能会恶化。
考虑你的固定线程池 - 如果你有5个长时间运行的任务,那么任何新任务都会产生一个新线程,完全破坏池的任何可能的收益。如果使用更灵活的执行程序 - 将共享某些线程,但并非总是如此。
经验法则是
答案 1 :(得分:6)
回答你的问题 - 是的,使用Executor比创建新线程更好,因为:
答案 2 :(得分:4)
根据Ordous的评论,我修改了我的代码,只使用一个池。
public class App extends Application {
private ThreadPoolExecutor mPool;
@Override
public void onCreate() {
super.onCreate();
mPool = new ThreadPoolExecutor(5, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new SynchronousQueue<Runnable>());
}
}
public void submitRunnableTask(Runnable task){
if(!mPool.isShutdown() && mPool.getActiveCount() != mPool.getMaximumPoolSize()){
mPool.submit(task);
} else {
new Thread(task).start(); // Actually this should never happen, just in case...
}
}
所以,我希望这对其他人有用,如果经验丰富的人对我的方法有一些评论,我将非常感谢他们的评论。