Java 短而频繁的作业:HandlerThread还是ThreadPoolExecutor?
首先,我无法确定标题应该是什么,所以如果不够具体,问题本身就是 我们有一个应用程序,它使用前台服务并永远保持活动状态,在这个服务中,需要在后台线程上运行频繁的数据库访问作业、网络访问作业等。一项工作本身消耗的时间很少,但工作本身是频繁的。显然,它们需要在工作线程上运行,所以我在这里询问我们应该遵循哪种设计 是一种结构,它创建单个线程并使用队列执行任务,但始终循环并等待消耗电源的消息,同时为每个作业创建多个线程并在作业完成时删除线程,但由于线程太多,可能会出现泄漏,甚至内存不足。作业计数可以是5,也可以是20,这取决于用户以某种方式的行为。而且,两份工作之间可能有5秒的间隔,或者一天的间隔,完全取决于用户。但是,请记住,应用程序将永远保持活动状态,并等待这些作业执行Java 短而频繁的作业:HandlerThread还是ThreadPoolExecutor?,java,android,multithreading,Java,Android,Multithreading,首先,我无法确定标题应该是什么,所以如果不够具体,问题本身就是 我们有一个应用程序,它使用前台服务并永远保持活动状态,在这个服务中,需要在后台线程上运行频繁的数据库访问作业、网络访问作业等。一项工作本身消耗的时间很少,但工作本身是频繁的。显然,它们需要在工作线程上运行,所以我在这里询问我们应该遵循哪种设计 是一种结构,它创建单个线程并使用队列执行任务,但始终循环并等待消耗电源的消息,同时为每个作业创建多个线程并在作业完成时删除线程,但由于线程太多,可能会出现泄漏,甚至内存不足。作业计数可以是5,
那么,对于这个特定的场合,哪一个更适合使用呢?线程池执行器还是处理程序线程?非常感谢您的建议。不要真的认为这是您正在运行的线程数量的问题,更多的是您希望它们如何运行。如果希望它们一次运行一个(即,一次只希望对数据库查询执行),则使用
HandlerThread
。如果需要多线程/线程池,请使用和Executor
根据我的经验,泄漏更多地取决于线程的编码方式,而不是所选择的实现
就我个人而言,我会使用
HandlerThread
,这里有一篇关于实现它们以及如何避免内存泄漏的好文章 警告:我不做Android工作,所以我不是这方面的专家。我的观点基于对Android文档的快速阅读
tl;博士
➥ 使用执行器而不是HandlerThread
Executors框架比HandlerThread
使用的传统Thread
工具更现代、更灵活、更强大。在HandlerThread中你能做的一切都可以在执行者身上做得更好
分歧
和之间的一大区别是第一个来自Android,而第二个来自Java。因此,如果要用Java做其他工作,您可能不想养成使用HandlerThread
的习惯
另一个很大的区别是年龄。android.os.HandlerThread
类继承自java.lang.Thread
,可以追溯到最初的android API级别1。Java中的线程
功能在设计上是有限的,尽管它的时间很好。在后来的Java中,这种功能被更现代、更灵活、更强大的功能所取代
遗嘱执行人
您的问题不清楚这些是重复性工作还是临时安排的工作。任何一个都可以由执行人处理
对于在特定时间运行一次的作业和定期计划作业,请使用。您可以通过指定延迟、等待执行的时间跨度来安排作业在特定时间运行一次。对于重复作业,可以指定等待、运行、等待、运行的数量,依此类推。我不会进一步讨论这个问题,因为您似乎在谈论零星的即时作业,而不是计划或重复作业。如果感兴趣,可以搜索堆栈溢出,因为在堆栈溢出上已多次涉及ScheduledExecutorService
单线程池
HandlerThread是创建单个线程的结构
如果要重新创建该单线程行为,请使用
把你的任务做好。通过lambda语法或常规语法,实现或使用(a)实现任一接口的类,(b)不定义类
Runnable sayHelloJob = new Runnable()
{
@Override
public void run ( )
{
System.out.println( "Hello. " + Instant.now() );
}
};
常规语法
Runnable sayHelloJob = new Runnable()
{
@Override
public void run ( )
{
System.out.println( "Hello. " + Instant.now() );
}
};
Lambda语法
Runnable sayBonjourJob = ( ) -> System.out.println( "Bonjour. " + Instant.now() );
向executor service提交任意数量的作业
es.submit( sayHelloJob ) ;
es.submit( sayBonjourJob ) ;
请注意,submit
方法返回一个。使用该Future
对象,您可以检查计算是否完成、等待其完成或检索计算结果。或者,您可以选择忽略上面代码中显示的Future
对象
固定线程池
如果需要多线程行为,只需使用不同类型的线程池创建执行器
ExecutorService es = Executors.newCachedThreadPool() ;
为单个提交作业队列(可运行的或可调用的对象)提供服务的线程数最大。这些线程将继续工作,并在出现故障时根据需要进行更换
ExecutorService es = Executors.newFixedThreadPool( 3 ) ; // Specify number of threads.
代码的其余部分保持不变。这就是使用ExecutorService
接口的好处:您可以更改executor服务的实现,以获得不同的行为,同时不破坏调用该executor服务的代码
缓存线程池
您的需求可能会得到更好的服务。与固定线程池那样立即创建和维护一定数量的线程不同,该线程池只在需要时创建线程,最多创建一个线程。当一个线程完成并静止超过一分钟时,线程终止。正如Javadoc所指出的,这非常适合“许多短期异步任务”,比如您的任务。但请注意,可能同时运行的线程没有上限。如果您的应用程序的性质是,您可能会经常看到许多作业同时到达,那么您可能希望使用不同的实现,而不是缓存线程池
ExecutorService es = Executors.newCachedThreadPool() ;
管理执行器和线程
但是由于线程太多,可能会出现泄漏,甚至内存不足
程序员和系统管理员的工作就是不让生产服务器负担过重。您需要监控生产中的性能。管理很简单