专业的JAVA编程教程与资源

网站首页 > java教程 正文

Java异步编程--Executor框架深入浅出

temp10 2024-10-21 12:23:31 java教程 14 ℃ 0 评论

一、同步与异步概念

同步是指进程在执行某个任务时,必须要等待该任务执行结束才能够执行其他的任务,则意味着阻塞,如InputStream.read()读取文件内容时,则在内核返回数据前该发起线程会被暂停。

异步则是指执行某个任务时不必等待其返回结果,可以继续执行其他的任务。

Java异步编程--Executor框架深入浅出

注意:同步并不代表着一定阻塞,如NIO的轮询以检查是否有数据,即该线程没有被收回CPU执行权限;而异步也并不一定代表是非阻塞的,如向线程池提交任务后马上调用Future.get()来获取该任务的处理结果(ThreadPoolExecutor.submit(someTask).get()),那么尽管该任务是异步执行的,但是其发起线程仍然可能由于Future.get()调用时该任务尚未被线程池执行结束而被阻塞。

二、Java Executor框架

在Java世界中通常在多线程编程以新建工作线程外(即创建Thread实例),还有常用且更优美的方式就是调用jdk提供的Java.util.concurrent.Executor接口,对任务的执行进行了抽象,隐藏其逻辑,让我们更好的关注任务本身!但是该接口也比较简单,功能有限,如不能返回任务的结果,其次该接口实现类中往往维护一些工作者线程,当我们不再需要一个Executor实例时,往往需要主动将该这些工作者线程停掉以释放相应的资源,而Executor则没有定义相应的方法!

而ExecutorService接口则可以解决上述问题,所以一般都使用接口,其默认的实现类为ThreadPoolExecutor。

三、工具类Executors

Executors主要提供了创建ExecutorService实例的快捷方法,除此之外还能返回默认的线程工厂以及将Runnable转换为Callable实例。具体如下:

	3.1 public static ExecutorService newCachedThreadPool() 
		 public static ExecutorService newCachedThreadPool(ThreadFactory tf)
			-- 适用于执行大量耗时短且提交比较频繁的任务,如果任务执行过长,可能导致线程池中的工作者线程无限制地增长,最后导致过的上下文切换,从而使得整个系统变慢!
 其内容实现相当于:
 new ThreadPoolExecutor(0,Integer.MAX_VALUE,60L,TimeUnit.SECONDS,new SynchronousQueue<Runnable>());
 即一个核心线程池大小为0,最大线程池大小不受限,工作者线程允许得最大空闲时间为60秒,内部以SynchronousQueue为工作队列得一个线程池!这种配置意味着该线程池中得所有工作者线程在空闲了指定得时间后都可以被自动清理掉。
 
 3.2 public static ExecutorService newFixedThreadPool(int nThreads)
 public static ExecutorService newFixedThreadPool(int nThreads,ThreadFactory tf)
 该线程池中的线程数永远不会超时、回收,都是固定的,所以在不需要的时候需主动将其关闭。
 其内部实现相当于:
 new ThreadPoolExecutor(nThreads,nThreads,0L,TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>());
 即一个以无界队列的工作队列,核心线程池大小与最大线程池大小均为nThreads且空闲线程不会被自动清理的线程池!
 
 3.3 public static ExecutorService newSingleThreadExecutor()
 public static ExecutorService newSingleThreadExecutor(ThreadFactory)
 适合用于单/多生成者---单消费者模式;或者用来方位了非线程安全对象而又不希望引入锁的任务。注意该返回类型无法转换成ThreadPoolExecutor。

四、异步任务的批量执行--CompletionService

尽管Future接口使得我们能够方便地获取异步任务的处理结果,但是如果需要一次性提交一批异步任务并获取这些任务的处理结果的话,那么仅使用Future接口会比较繁琐!而CompletionService则提供了便利!

通过CompletionService#take()获取任务结果Future

五、计划任务--ScheduledExecutorService

5.1 延迟执行提交的任务,包括以下两种方法:

<V> ScheduledFuture<V> schedule(Callable<V> callable,long delay,TimeUnit unit)

ScheduledFuture<?> schedule(Runnable command,long delay,TimeUnit unit)

表示提交的任务自其提交的那一刻后以unit为单位的delay时间后执行!

5.2周期性地执行提交的任务

ScheduledFuture<?> scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit)

ScheduledFuture<?> scheduleWithFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit)

最后有个留个问题,就是除了Runnable接口和Callable接口这两个对任务处理逻辑的抽象外,常用的还有哪些接口,他们的比较以及你会用吗?

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表