通常,使用Java开发并发程序时,我们创建Runnable对象,然后创建对应的线程Thead对象来执行它们。Java 5之后,Java并发API提供了Executor框架,主要包括Executor接口,它的子接口ExecutorService,以及实现上述两个接口的ThreadPoolExecutor类。
这种机制使得任务的创建和任务的执行分离,使用executor,开发者只需要实现Runnable对象,把对象传递给executor即可。Executor会负责它们的执行、实例化并调度相关的线程。不止于此,通过使用线程池可以改善性能。当向Executor传递任务时,它会尝试使用已池化的线程来执行此任务,避免不断地创建新线程。
本文只介绍一个最基本的threadpoolexecutor的例子,更复杂任务将在后续帖子中介绍。
1. 创建待执行的任务
class Task implements Runnable { private String name; public Task(String name) { this.name = name; } public String getName() { return name; } @Override public void run() { try { Long duration = (long) (Math.random() * 10); System.out.println("Doing a task during : " + name); TimeUnit.SECONDS.sleep(duration); } catch (InterruptedException e) { e.printStackTrace(); } } }
2. 使用Executors执行任务
现在我们只需要创建一个ThreadPoolExecutor实例,将任务传递给它的execute()方法。
package com.howtodoinjava.demo.multithreading; import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class BasicThreadPoolExecutorExample { public static void main(String[] args) { //Use the executor created by the newCachedThreadPool() method //only when you have a reasonable number of threads //or when they have a short duration. ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newCachedThreadPool(); for (int i = 0; i <= 5; i++) { Task task = new Task("Task " + i); System.out.println("A new task has been added : " + task.getName()); executor.execute(task); } executor.shutdown(); } }
输出:
A new task has been added : Task 0 A new task has been added : Task 1 A new task has been added : Task 2 A new task has been added : Task 3 A new task has been added : Task 4 A new task has been added : Task 5 Doing a task during : Task 5 Doing a task during : Task 0 Doing a task during : Task 2 Doing a task during : Task 1 Doing a task during : Task 4 Doing a task during : Task 3
一些关键点:
1. ThreadProolExecutor有四个不同的构造器,考虑到其复杂性,Java并发API提供了Executors类来构建执行器和相关对象。尽管我们可以直接通过其构造函数来生成ThreadPoolExecutor,使用Executors类是更加推荐的方式。
2. 上述例子中中我们创建了一个缓存线程池(cached thread pool),当执行新任务时如果需要则创建新线程;当已有线程完成了它们执行的任务之后可以重用。缓存线程池的一个缺点在于它会不断创建新的线程,如果向此executor发送了过多任务,可能会导致系统负载过高。通过固定线程线程池可以解决这个问题,后面详述
3. 关于ThreadPoolExecutor类的重要一点(也适用于其他的executor),你必须显式地结束它。否则它将会一直执行下去,程序将不会结束。当executor没有任务执行时,它持续等待新的任务,并不会结束执行。Java应用程序只有当所有的非守护线程都结束后才会停止执行。所以如果不结束executor,你的程序将永远不会结束。
4. 为了结束executor,你可以使用ThreadPoolExecutor类的shutdown()方法。当executor结束所有的待执行任务时,它将会停止运行。当调用shutdown()方法之后,如果尝试把另外一个任务发送给此执行器,执行器将会拒绝并抛出RejectedExecutionException异常。
5. ThreadPoolExecutor类提供了用于获取状态信息的一组方法,在示例程序中,我们可以使用getPoolSize(),getActiveCount()以及getCompletedTaskCount()方法以获取线程池大小,线程数量,此执行器执行完成的任务数量等信息。你也可以调用 getLargestPoolSize()方法获取此线程池曾经存在的最大线程数量。
6. ThreadPoolExecutor类也提供用于结束execuor执行的其他相关方法:
- shutdownNow():此方法会将execuor立刻关闭。挂起的任务将不会执行。它返回所有挂起任务的列表。正在执行呃任务将继续执行,但此方法不会等待它们执行完成。
- isTerminated():当shutdown()或shutdownNow()方法被调用,并且executor结束关闭过程后,此方法返回true。
- isShutdown():当你调用shutdown()方法之后,此方法返回true。
- awaitTermination(long timeout, TimeUnit unit):此方法阻塞所有的调用线程,直到此执行器任务结束或超时时间到。TimeUnit类包含了如下枚举值:DAYS,HOURS,MICROSECONDS等。
相关推荐
一个关于java 线程池的例子,也适合android
该文档详细记录了Executor框架结构、使用示意图、ThreadPoolExecutor使用示例、线程池原理分析、几种常见线程池(FixedThreadPool、SingleThreadExecutor、CachedThreadPool)的详解以及线程池大小确定等内容
从Python3.2开始,标准库为我们提供了 concurrent.futures 模块,它提供了 ThreadPoolExecutor (线程池)和ProcessPoolExecutor (进程池)两个类。 相比 threading 等模块,该模块通过 submit 返回的是一个 future ...
提供工厂方法来创建不同类型的线程池,这篇文章主要介绍了Java ThreadPoolExecutor 线程池的使用介绍,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来...
主要介绍了Java线程池ThreadPoolExecutor原理及使用实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
# 使用 8 除以用户输入的整数并且输出 result = 8 / num print(result) except ValueError: print("请输入正确的整数") except Exception as result: print("未知错误 %s" % result) else: print("未发生异常...
主要给大家介绍了关于java线程池使用后到底要不要关闭的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
本文实例讲述了Python 线程池...from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor import os,time,random def task(n): print('%s is runing' %os.getpid()) time.sleep(random.randint(1,3))
3.4.2 示例:使用Volatile类型来发布不可变对象40 3.5 安全发布41 3.5.1 不正确的发布:正确的对象被破坏42 3.5.2 不可变对象与初始化安全性42 3.5.3 安全发布的常用模式43 3.5.4 事实不可变对象44 3.5.5 可变...
MVP安卓 这是一个非常简单的应用程序,在导航菜单中显示伟大的艺术家名字。 我使用模型-视图-演示者模式来构建应用程序。 后台任务的多线程使用 ThreadPoolExecutor 完成。 应用演示
4.4.3 自定义View示例 202 4.4.4 自定义View的思想 217 第5章 理解RemoteViews 218 5.1 RemoteViews的应用 218 5.1.1 RemoteViews在通知栏上的应用 219 5.1.2 RemoteViews在桌面小部件上的应用 221 5.1.3 ...
在前面的文章中,我们...我们来详细讲解一下Java的线程池,首先我们从核心的ThreadPoolExecutor类中的方法讲起,然后再讲述它的实现原理,接着给出了它的使用示例,后讨论了一下如何合理配置线程池的大小。 以下是
JAVA多线程回显服务器 Prog2 Java LP SIL的项目/ Vianey Benjamin-Bodet Cindy课程 Config.txt 配置文件示例: { "Implementation": "1", ...使用ThreadPoolExecutor管理线程空闲 使用配置文件选择实现
"""脚本功能说明:使用 tinypng api,一键批量压缩指定文件(夹)所有文件""" import os import sys from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor # 线程池,进程池 import json import ...
4.4.3 自定义View示例 / 202 4.4.4 自定义View的思想 / 217 第5章 理解RemoteViews / 218 5.1 RemoteViews的应用 / 218 5.1.1 RemoteViews在通知栏上的应用 / 219 5.1.2 RemoteViews在桌面小部件上的...
主要介绍了深入理解Java编程线程池的实现原理,涉及ThreadPoolExecutor类,线程池实现原理及示例等相关内容,具有一定参考价值,需要的朋友可以了解下。