Java Android中的new Thread(task).start()与ThreadPoolExecutor.submit(task)的比较
在我的Android项目中,我有很多地方需要异步运行一些代码(web请求、对db的调用等)。这不是长时间运行的任务(最多几秒钟)。 直到现在,我一直在做这类事情,创建一个新线程,通过任务传递一个新的runnable。但最近我读了一篇关于Java中线程和并发性的文章,并理解为每个任务创建一个新线程并不是一个好的决定 因此,现在我在我的Java Android中的new Thread(task).start()与ThreadPoolExecutor.submit(task)的比较,java,android,multithreading,asynchronous,threadpoolexecutor,Java,Android,Multithreading,Asynchronous,Threadpoolexecutor,在我的Android项目中,我有很多地方需要异步运行一些代码(web请求、对db的调用等)。这不是长时间运行的任务(最多几秒钟)。 直到现在,我一直在做这类事情,创建一个新线程,通过任务传递一个新的runnable。但最近我读了一篇关于Java中线程和并发性的文章,并理解为每个任务创建一个新线程并不是一个好的决定 因此,现在我在我的应用程序类中创建了一个线程池执行器,它包含5个线程。 代码如下: public class App extends Application { privat
应用程序
类中创建了一个线程池执行器
,它包含5个线程。
代码如下:
public class App extends Application {
private ThreadPoolExecutor mPool;
@Override
public void onCreate() {
super.onCreate();
mPool = (ThreadPoolExecutor)Executors.newFixedThreadPool(5);
}
}
我还有一个向执行者提交可运行任务的方法:
public void submitRunnableTask(Runnable task){
if(!mPool.isShutdown() && mPool.getActiveCount() != mPool.getMaximumPoolSize()){
mPool.submit(task);
} else {
new Thread(task).start();
}
}
因此,当我想在代码中运行异步任务时,我会获取App
的实例,并调用submitRunnableTask
方法将runnable传递给它。如您所见,我还检查线程池是否有空闲线程来执行我的任务,如果没有,我将创建一个新线程(我不认为会发生这种情况,但无论如何……我不希望我的任务在队列中等待并减慢应用程序的速度)
在应用程序的onTerminate
回调方法中,我关闭了池
所以我的问题是:这种模式比在代码中创建新线程更好吗?我的新方法有哪些优点和缺点?它会导致我还没有意识到的问题吗?你能给我一些更好的建议来管理我的异步任务吗
另外,我在Android和Java方面有一些经验,但我远不是一个并发专家),所以在这类问题中可能有一些方面我不太了解。任何建议都将不胜感激。回答您的问题-是的,使用Executor比创建新线程要好,因为:
此答案假设您的任务很短 这种模式比在代码中创建新线程更好吗 虽然更好,但离理想还很远。您仍在为短任务创建线程。相反,您只需要创建一个不同类型的线程池,例如通过
Executors.newScheduledThreadPool(int-corePoolSize)
行为上有什么不同
将始终有一组线程可供使用,如果所有线程都很忙,则会将新任务放入队列中FixedThreadPool
- 由
类创建的(默认)Executors
,即使在空闲时,也会保留一个最小的线程池。如果新任务进入时所有线程都很忙,则会为其创建一个新线程,并在完成后60秒处理该线程,除非再次需要它ScheduledThreadPool
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue)
public ThreadPoolExecutor(int-corePoolSize,
int maximumPoolSize,
长时间,
时间单位,
阻塞队列(工作队列)
各种选项允许您微调行为
如果某些任务很长…
我是说长。在应用程序生命周期的大部分时间(实时双向连接?服务器端口?多播侦听器?)。在这种情况下,将Runnable
放在执行器中是有害的-标准执行器的设计不是为了应对这种情况,它们的性能将恶化
想想你的固定线程池——如果你有5个长时间运行的任务,那么任何新任务都会产生一个新线程,完全破坏池中任何可能的收益。如果您使用更灵活的执行器,则会共享一些线程,但并不总是如此
经验法则是
- 如果任务很短,请使用执行者
- 如果这是一个很长的任务-确保您的执行者能够处理它(即,它要么没有最大池大小,要么没有足够的最大线程数来处理一段时间内多出的一个线程)
- 如果它是一个需要始终与主线程并行运行的并行进程,请使用另一个线程
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...
}
}
公共类应用程序扩展应用程序{
私有线程池执行器mPool;
@凌驾
public void onCreate(){
super.onCreate();
mPool=new ThreadPoolExecutor(5,Integer.MAX_值,1,TimeUnit.MINUTES,new SynchronousQueue());
}
}
公共void submitRunnableTask(可运行任务){
如果(!mPool.isshutton()&&mPool.getActiveCount()!=mPool.getMaximumPoolSize()){
mPool.submit(任务);
}否则{
new Thread(task).start();//实际上这永远不会发生,以防万一。。。
}
}
因此,我希望这对其他人有用,如果更有经验的人对我的方法有一些评论,我将非常感谢他们的评论 线程池避免了为每个新任务创建和销毁线程的大量开销。此外,它允许您使用某种策略来控制在任何给定时刻存在多少个工作线程,而不是让它在任何情况下发生。此外,如果你的应用程序需要这样做的话,它可以让你不用重新发明机器来关闭它们。我为任务并行和数据并行应用程序管理几个开源项目。以下是一篇适用于Android的文章:@e