Java Android中的new Thread(task).start()与ThreadPoolExecutor.submit(task)的比较

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

在我的Android项目中,我有很多地方需要异步运行一些代码(web请求、对db的调用等)。这不是长时间运行的任务(最多几秒钟)。 直到现在,我一直在做这类事情,创建一个新线程,通过任务传递一个新的runnable。但最近我读了一篇关于Java中线程和并发性的文章,并理解为每个任务创建一个新线程并不是一个好的决定

因此,现在我在我的
应用程序
类中创建了一个
线程池执行器
,它包含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比创建新线程要好,因为:

  • Executor提供了不同线程池的选择。它允许重用已经存在的线程,这会提高性能,因为创建线程是一项昂贵的操作
  • 在线程死亡的情况下,执行器可以用新线程替换它,而不会影响应用程序
  • 更改多线程策略要容易得多,因为只需要更改Executor实现

  • 此答案假设您的任务很短

    这种模式比在代码中创建新线程更好吗

    虽然更好,但离理想还很远。您仍在为短任务创建线程。相反,您只需要创建一个不同类型的线程池,例如通过
    Executors.newScheduledThreadPool(int-corePoolSize)

    行为上有什么不同

    • FixedThreadPool
      将始终有一组线程可供使用,如果所有线程都很忙,则会将新任务放入队列中
    • Executors
      类创建的(默认)
      ScheduledThreadPool
      ,即使在空闲时,也会保留一个最小的线程池。如果新任务进入时所有线程都很忙,则会为其创建一个新线程,并在完成后60秒处理该线程,除非再次需要它
    第二个线程允许您自己不创建新线程。这种行为可以在没有“预定”部分的情况下实现,但是您必须自己构造执行器。构造函数是

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue)
    
    public ThreadPoolExecutor(int-corePoolSize,
    int maximumPoolSize,
    长时间,
    时间单位,
    阻塞队列(工作队列)
    
    各种选项允许您微调行为

    如果某些任务很长…

    我是说长。在应用程序生命周期的大部分时间(实时双向连接?服务器端口?多播侦听器?)。在这种情况下,将
    Runnable
    放在执行器中是有害的-标准执行器的设计不是为了应对这种情况,它们的性能将恶化

    想想你的固定线程池——如果你有5个长时间运行的任务,那么任何新任务都会产生一个新线程,完全破坏池中任何可能的收益。如果您使用更灵活的执行器,则会共享一些线程,但并不总是如此

    经验法则是

    • 如果任务很短,请使用执行者
    • 如果这是一个很长的任务-确保您的执行者能够处理它(即,它要么没有最大池大小,要么没有足够的最大线程数来处理一段时间内多出的一个线程)
    • 如果它是一个需要始终与主线程并行运行的并行进程,请使用另一个线程

    根据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...
        }
    }
    
    公共类应用程序扩展应用程序{
    私有线程池执行器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