大数据处理之Java线程池使用

合集下载

线程池的运行流程

线程池的运行流程

线程池的运行流程线程池是一种用来管理和复用线程的技术,它可以有效地提高多线程程序的性能和资源利用率。

线程池通过预先创建一定数量的线程,并将任务分配给这些线程来处理,避免了不断创建和销毁线程的开销。

线程池的运行流程如下:1. 线程池的创建:线程池的创建需要确定线程池的大小、任务队列的长度、线程的优先级等参数。

可以通过ThreadPoolExecutor类创建线程池,其中ThreadPoolExecutor构造函数的参数可以指定线程池的大小、任务队列的长度等。

2.初始化线程池:创建线程池之后,线程池会创建一定数量的线程,这些线程处于等待状态,等待任务的到来。

线程池还会创建一个任务队列,用来存放待执行的任务。

3. 提交任务:当需要执行任务时,可以通过execute方法提交任务到线程池。

线程池会将任务放入任务队列中,等待线程来执行。

如果任务队列已满,线程池会根据配置的策略进行处理,比如直接丢弃任务、抛出异常等。

4.选择线程执行任务:线程池会从任务队列中选择一个任务,然后从线程池中选择一个空闲的线程来执行任务。

线程池可以根据多种策略来选择线程,比如先进先出、最近未使用等。

5.执行任务:选中线程开始执行任务。

线程执行任务期间,会不断从任务队列中获取任务并执行,直到任务队列为空或线程池被关闭。

6.线程复用:任务执行完毕之后,线程不会被销毁,而是回到线程池中,等待新的任务。

这样可以减少线程的创建和销毁的开销,提高了线程的复用率。

7.监控和管理:线程池通常会提供一些监控和管理的功能,比如可以监控线程池的运行状态、线程的活动数、任务队列的长度等,还可以根据需求进行动态调整线程池的大小、任务队列的长度等。

8. 关闭线程池:当不再需要线程池时,可以调用shutdown方法来关闭线程池。

关闭线程池后,线程池不再接受新的任务,但会继续执行已提交的任务。

可以通过awaitTermination方法等待线程池中所有任务执行完毕,然后关闭线程池。

java线程池的使用例子

java线程池的使用例子

java线程池的使用例子随着计算机技术的不断发展,我们的软件系统越来越复杂,程序的性能要求也越来越高。

在这样的背景下,线程池成为了一种非常重要的工具。

Java线程池是Java提供的一种简单易用的线程管理工具,可以帮助我们更好地管理程序中的线程,提高程序的性能和稳定性。

本文将通过一个实际的例子来介绍Java线程池的使用方法和注意事项。

希望读者可以通过本文的学习,更好地掌握Java线程池的使用技巧。

一、什么是线程池?在介绍Java线程池之前,我们需要先了解什么是线程池。

线程池是一种管理线程的机制,可以帮助我们更好地管理程序中的线程,提高程序的性能和稳定性。

线程池的主要作用是为每个任务分配一个线程,当任务完成后,线程会被回收并可供下一个任务使用。

这样,线程的创建和销毁的开销就可以得到控制,避免了频繁创建和销毁线程所带来的性能损失。

二、Java线程池的使用方法1. 创建线程池Java线程池的创建方式非常简单,只需要使用ThreadPoolExecutor类即可。

以下是一个简单的线程池创建代码: ```ExecutorService executor =Executors.newFixedThreadPool(5);```这个代码创建了一个固定大小为5的线程池。

如果需要创建其他类型的线程池,可以使用其他的静态工厂方法,如newCachedThreadPool()、newSingleThreadExecutor()等。

2. 提交任务创建好线程池之后,我们就可以向线程池提交任务了。

以下是一个简单的线程池提交任务代码:```executor.submit(new Runnable() {@Overridepublic void run() {// 执行任务}});```这个代码提交了一个Runnable类型的任务,线程池会自动为其分配一个线程执行。

如果需要提交其他类型的任务,可以使用Callable、Future等接口。

JAVA多线程的使用场景与注意事项总结

JAVA多线程的使用场景与注意事项总结

JAVA多线程的使用场景与注意事项总结Java多线程是指在一个程序中同时运行多个线程,每个线程都有自己的执行代码,但是又共享同一片内存空间和其他系统资源。

多线程的使用场景和注意事项是我们在开发中需要关注的重点,下面将详细进行总结。

一、Java多线程的使用场景:1.提高程序的执行效率:多线程可以充分利用系统资源,将一些耗时的操作放到一个线程中执行,避免阻塞主线程,提高程序的执行效率。

2.实现并行计算:多线程可以将任务拆分成多个子任务,每个子任务分配给一个线程来执行,从而实现并行计算,提高计算速度。

3.响应性能提升:多线程可以提高程序的响应性能,比如在用户界面的开发中,可以使用多线程来处理用户的输入和操作,保证界面的流畅性和及时响应。

4.实时性要求高:多线程可以实现实时性要求高的任务,比如监控系统、实时数据处理等。

5.任务调度与资源管理:多线程可以实现任务的调度和资源的管理,通过线程池可以更好地掌控任务的执行情况和使用系统资源。

二、Java多线程的注意事项:1.线程安全性:多线程操作共享资源时,要注意线程安全问题。

可以通过使用锁、同步方法、同步块等方式来解决线程安全问题。

2.死锁:多线程中存在死锁问题,即多个线程相互等待对方释放资源,导致程序无法继续执行。

要避免死锁问题,应尽量减少同步块的嵌套和锁的使用。

3.内存泄漏:多线程中存在内存泄漏问题,即线程结束后,线程的资源没有得到释放,导致内存占用过高。

要避免内存泄漏问题,应及时释放线程资源。

4.上下文切换:多线程的切换会带来上下文切换的开销,影响程序的执行效率。

要注意合理分配线程的数量,避免过多线程的切换。

5. 线程同步与通信:多线程之间需要进行同步和通信,以保证线程之间的正确协调和数据的一致性。

可以使用synchronized关键字、wait(和notify(方法等方式进行线程同步和通信。

6.线程池的使用:在多线程编程中,可以使用线程池来管理线程的创建和销毁,可以减少线程的创建和销毁的开销,提高程序的性能。

Java千万级别数据处理与优化

Java千万级别数据处理与优化

Java千万级别数据处理与优化随着互联网的发展,数据规模异常的庞大。

对于Java开发人员来说,面对这种情况,我们需要从性能和优化的角度思考,从而使我们的程序在处理海量数据时更有效率、更加可靠。

一、数据处理1. 数据读取优化数据读取是数据处理的第一步,良好的数据读取优化可以最大限度地提高程序的效率。

在数据读取方面,我们需要注重以下几个方面的优化:(1)缓存读取:对于内存中需要反复读取的数据,我们应该缓存读取,避免多次访问磁盘带来的性能损耗。

(2)文件切割:对于大文件的读取,我们可以将其切割成多个小文件,以便于多线程同时读取,并且有效减少了每个线程读取文件大小的开销。

(3)使用BufferedInputStream和BufferedReader:Java中提供了BufferedInputStream和BufferedReader这两种缓存读取的方式,可以有效地提高文件读取的效率。

2. 数据存储优化在面对千万级别的数据时,数据的存储也是我们需要优化的重要环节。

在数据存储方面,我们需要注重以下几个方面的优化:(1)使用内存存储:对于频繁读写的数据,我们应该尽量使用内存存储,避免频繁的磁盘读写,从而提高程序效率。

(2)使用NoSQL数据库:对于大规模的数据存储,我们可以使用NoSQL数据库来代替传统的关系型数据库,NoSQL数据库对分布式存储的支持更加完善,可以提高数据存储的效率。

(3)批量操作:在实际开发中,我们应该尽量采用批量操作的方式进行数据存储,这样可以有效提高数据处理的效率。

二、数据处理算法1. 分治算法分治算法是一种非常常见的算法,可以用于解决很多常见的数据处理问题。

在数据分析处理过程中,分治算法可以用来将庞大的数据集划分成多个小数据集,然后并行处理每个小数据集,最后合并结果。

通过这种方法,可以有效提高程序的处理效率。

2. MapReduce算法MapReduce算法是一种分布式数据处理算法,可以对千万级别的数据进行优化。

Java大规模数据处理解析海量数据的技巧

Java大规模数据处理解析海量数据的技巧

Java大规模数据处理解析海量数据的技巧在处理大规模数据时,Java是一种常用的编程语言。

然而,由于海量数据的处理可能涉及到效率、内存管理以及算法优化等方面的挑战,开发人员需要掌握一些技巧来解析这些数据。

本文将介绍一些Java大规模数据处理的技巧,帮助开发人员更好地处理海量数据。

一、数据分块处理在处理大规模数据时,内存管理是一个重要的问题。

当数据量超过内存限制时,我们需要将数据分块处理,以避免内存溢出。

可以使用Java的流式处理机制,通过迭代的方式读取数据,每次处理一块数据,减少内存的消耗。

例如,可以使用BufferedReader的readLine()方法逐行读取文件,然后对每行数据进行处理。

二、并行处理并行处理是指同时处理多个数据块的技术,可以显著提高处理大规模数据的效率。

Java提供了多线程和线程池的机制,可以将数据分成多个部分,并行地处理每个部分。

通过合理设置线程池的大小,可以充分利用计算资源,提高程序的运行效率。

三、使用适当的数据结构在处理大规模数据时,选择适当的数据结构非常重要。

不同的数据结构对于不同的操作具有不同的时间复杂度,选择合适的数据结构可以提高程序的效率。

例如,如果需要频繁地插入和删除数据,可以选择链表或树等数据结构;如果需要随机访问数据,可以选择数组或哈希表等数据结构。

根据不同的需求,选择合适的数据结构可以提高程序的性能。

四、优化算法算法的选择也是解析海量数据的关键。

优化算法可以提高程序的效率,减少资源的消耗。

例如,对于排序操作,可以选择高效的排序算法,如快速排序或归并排序,而不是简单的冒泡排序。

另外,可以使用适当的数据结构和算法来进行数据过滤、去重等操作,减少不必要的计算。

五、使用缓存缓存是提高程序性能的有效方式之一。

当程序需要频繁地访问某些数据时,可以使用缓存将这些数据存储起来,避免重复计算和访问。

在Java中,可以使用HashMap等数据结构来实现缓存。

通过在内存中存储一部分数据,可以提高程序的响应速度和效率。

java 线程池 purge方法

java 线程池 purge方法

java 线程池 purge方法Java线程池是Java多线程编程中非常重要的概念和工具。

在多线程编程中,线程池可以有效地管理和控制线程的创建和销毁,提高程序的性能和稳定性。

而线程池的`purge()`方法则是线程池中的一个重要方法,用于清除线程池中已经完成的任务。

我们来了解一下线程池的基本概念。

线程池是一种线程管理的机制,它包含了一组线程,用于执行提交的任务。

通过线程池,我们可以避免频繁创建和销毁线程的开销,提高线程的复用性和执行效率。

Java提供了`java.util.concurrent`包下的`Executor`接口和`ExecutorService`接口来支持线程池的使用。

在Java线程池中,`purge()`方法是一个非常有用的方法。

它的作用是清除线程池中已经完成的任务,以便释放内存资源。

当线程池中的任务执行完毕后,这些任务会被保留在线程池中,等待下次使用。

而`purge()`方法可以清除这些已经完成的任务,使得线程池中只保留尚未执行的任务,避免占用过多的内存资源。

那么,我们如何使用`purge()`方法呢?在Java中,线程池是通过`ExecutorService`接口的实现类来创建和管理的。

要使用`purge()`方法,我们首先需要创建一个线程池对象。

可以使用`Executors`类提供的静态方法来创建不同类型的线程池,例如`newFixedThreadPool()`、`newCachedThreadPool()`等。

创建完线程池对象后,我们可以通过调用`purge()`方法来清除已经完成的任务。

`purge()`方法会返回线程池中已经完成的任务数量,并将这些任务从线程池中移除。

这样,我们就可以及时释放内存资源,防止内存泄漏的发生。

需要注意的是,`purge()`方法只能清除已经完成的任务,对于正在运行的任务无法清除。

如果想要终止正在运行的任务,可以使用`shutdownNow()`方法来强制停止线程池中的所有任务。

java线程池异步调用方法

java线程池异步调用方法

java线程池异步调用方法Java线程池可以用于异步调用方法。

实现步骤如下:1. 定义一个线程池对象javaExecutorService executorService = Executors.newFixedThreadPool(10);2. 定义一个Callable对象,用于异步运行方法javaCallable<String> callable = () -> {执行异步方法return "result";};3. 提交Callable对象到线程池中,并获得Future对象javaFuture<String> future = executorService.submit(callable);4. 使用Future对象获取异步执行方法的结果javaString result = future.get();完整示例代码如下:javaimport java.util.concurrent.Callable;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;public class ThreadPoolExample {public static void main(String[] args) throws Exception {ExecutorService executorService =Executors.newFixedThreadPool(10);Callable<String> callable = () -> {执行异步方法return "result";};Future<String> future = executorService.submit(callable);String result = future.get();System.out.println(result);executorService.shutdown();}}。

使用java多线程分批处理数据工具类

使用java多线程分批处理数据工具类

使⽤java多线程分批处理数据⼯具类最近由于业务需要,数据量⽐较⼤,需要使⽤多线程来分批处理,提⾼处理效率和能⼒,于是就写了⼀个通⽤的多线程处理⼯具,只需要实现⾃⼰的业务逻辑就可以正常使⽤,现在记录⼀下主要是针对⼤数据量list,将list划分多个线程处理ResultBean类:返回结果统⼀beanpackage mon.model;import java.io.Serializable;import com.alibaba.fastjson.JSON;/*** 返回结果统⼀bean** ResultBean<BR>* 创建⼈:wangbeidou <BR>* 时间:2018年4⽉12⽇-下午3:49:46 <BR>* @version 2.0**/public class ResultBean<T> implements Serializable {private static final long serialVersionUID = 1L;// 成功状态public static final int SUCCESS = 1;// 处理中状态public static final int PROCESSING = 0;// 失败状态public static final int FAIL = -1;// 描述private String msg = "success";// 状态默认成功private int code = SUCCESS;// 备注private String remark;// 返回数据private T data;public ResultBean() {super();}public ResultBean(T data) {super();this.data = data;}/*** 使⽤异常创建结果*/public ResultBean(Throwable e) {super();this.msg = e.toString();this.code = FAIL;}/**** 实例化结果默认成功状态<BR>* ⽅法名:newInstance<BR>* 创建⼈:wangbeidou <BR>* 时间:2018年4⽉12⽇-下午3:51:26 <BR>* @return ResultBean<T><BR>* @exception <BR>* @since 2.0*/public static <T> ResultBean<T> newInstance() {ResultBean<T> instance = new ResultBean<T>();//默认返回信息instance.code = SUCCESS;/**** 实例化结果默认成功状态和数据<BR>* ⽅法名:newInstance<BR>* 创建⼈:wangbeidou <BR>* 时间:2018年5⽉10⽇-下午2:13:16 <BR>* @param data* @return ResultBean<T><BR>* @exception <BR>* @since 2.0*/public static <T> ResultBean<T> newInstance(T data) {ResultBean<T> instance = new ResultBean<T>();//默认返回信息instance.code = SUCCESS;instance.msg = "success";instance.data = data;return instance;}/**** 实例化返回结果<BR>* ⽅法名:newInstance<BR>* 创建⼈:wangbeidou <BR>* 时间:2018年4⽉12⽇-下午4:00:53 <BR>* @param code* @param msg* @return ResultBean<T><BR>* @exception <BR>* @since 2.0*/public static <T> ResultBean<T> newInstance(int code, String msg) {ResultBean<T> instance = new ResultBean<T>();//默认返回信息instance.code = code;instance.msg = msg;return instance;}/**** 实例化返回结果<BR>* ⽅法名:newInstance<BR>* 创建⼈:wangbeidou <BR>* 时间:2018年4⽉12⽇-下午4:00:35 <BR>* @param code* @param msg* @param data* @return ResultBean<T><BR>* @exception <BR>* @since 2.0*/public static <T> ResultBean<T> newInstance(int code, String msg, T data) { ResultBean<T> instance = new ResultBean<T>();//默认返回信息instance.code = code;instance.msg = msg;instance.data = data;return instance;}/**** 设置返回数据<BR>* ⽅法名:setData<BR>* 创建⼈:wangbeidou <BR>* 时间:2018年4⽉12⽇-下午3:52:01 <BR>* @param data* @return ResultBean<T><BR>* @exception <BR>* @since 2.0*/public ResultBean<T> setData(T data){this.data = data;return this;}/**** 设置结果描述<BR>* @return ResultBean<T><BR>* @exception <BR>* @since 2.0*/public ResultBean<T> setMsg(String msg){this.msg = msg;return this;}/**** 设置状态<BR>* ⽅法名:setCode<BR>* 创建⼈:wangbeidou <BR>* 时间:2018年4⽉12⽇-下午4:17:56 <BR>* @param code* @return ResultBean<T><BR>* @exception <BR>* @since 2.0*/public ResultBean<T> setCode(int code){this.code = code;return this;}/**** 设置备注)<BR>* ⽅法名:setRemark<BR>* 创建⼈:wangbeidou <BR>* 时间:2018年4⽉12⽇-下午5:47:29 <BR>* @param remark* @return ResultBean<T><BR>* @exception <BR>* @since 2.0*/public ResultBean<T> setRemark(String remark){this.remark = remark;return this;}/**** 设置成功描述和返回数据<BR>* ⽅法名:success<BR>* 创建⼈:wangbeidou <BR>* 时间:2018年4⽉12⽇-下午3:52:58 <BR>* @param msg* @param data* @return ResultBean<T><BR>* @exception <BR>* @since 2.0*/public ResultBean<T> success(String msg, T data){ this.code = SUCCESS;this.data = data;this.msg = msg;return this;}/**** 设置成功返回结果描述<BR>* ⽅法名:success<BR>* 创建⼈:wangbeidou <BR>* 时间:2018年4⽉12⽇-下午3:53:31 <BR>* @param msg* @return ResultBean<T><BR>* @exception <BR>* @since 2.0*/public ResultBean<T> success(String msg){this.code = SUCCESS;this.msg = msg;return this;}/**** 设置处理中描述和返回数据<BR>* @param data* @return ResultBean<T><BR>* @exception <BR>* @since 2.0*/public ResultBean<T> processing(String msg, T data){ this.code = PROCESSING;this.data = data;this.msg = msg;return this;}/**** 设置处理中返回结果描述<BR>* ⽅法名:success<BR>* 创建⼈:wangbeidou <BR>* 时间:2018年4⽉12⽇-下午3:53:31 <BR>* @param msg* @return ResultBean<T><BR>* @exception <BR>* @since 2.0*/public ResultBean<T> processing(String msg){this.code = PROCESSING;this.msg = msg;return this;}/**** 设置失败返回描述和返回数据<BR>* ⽅法名:fail<BR>* 创建⼈:wangbeidou <BR>* 时间:2018年4⽉12⽇-下午3:54:04 <BR>* @param msg* @param data* @return ResultBean<T><BR>* @exception <BR>* @since 2.0*/public ResultBean<T> fail(String msg, T data){this.code = FAIL;this.data = data;this.msg = msg;return this;}/**** 设置失败返回描述<BR>* ⽅法名:fail<BR>* 创建⼈:wangbeidou <BR>* 时间:2018年4⽉12⽇-下午3:54:32 <BR>* @param msg* @return ResultBean<T><BR>* @exception <BR>* @since 2.0*/public ResultBean<T> fail(String msg){this.code = FAIL;this.msg = msg;return this;}public T getData() {return data;}public String getMsg() {return msg;}public int getCode() {return code;}public String getRemark() {return remark;}/**** 时间:2018年4⽉12⽇-下午4:42:28 <BR>* @return String<BR>* @exception <BR>* @since 2.0*/public String json(){return JSON.toJSONString(this);}}View CodeITask接⼝:实现⾃⼰的业务package mon.multi.execute;import java.util.Map;/*** 任务处理接⼝* 具体业务逻辑可实现该接⼝* T 返回值类型* E 传⼊值类型* ITask<BR>* 创建⼈:wangbeidou <BR>* 时间:2018年8⽉4⽇-下午6:12:32 <BR>* @version 2.0**/public interface ITask<T, E> {/**** 任务执⾏⽅法接⼝<BR>* ⽅法名:execute<BR>* 创建⼈:wangbeidou <BR>* 时间:2018年8⽉4⽇-下午6:13:44 <BR>* @param e 传⼊对象* @param params 其他辅助参数* @return T<BR> 返回值类型* @exception <BR>* @since 2.0*/T execute(E e, Map<String, Object> params);}View CodeHandleCallable类:实现Callable接⼝,来处理任务package mon.multi.execute;import java.util.ArrayList;import java.util.List;import java.util.Map;import java.util.concurrent.Callable;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import mon.model.ResultBean;/***** HandleCallable<BR>* 创建⼈:wangbeidou <BR>* 时间:2018年8⽉4⽇-上午11:55:41 <BR>** @version 2.0**/@SuppressWarnings("rawtypes")public class HandleCallable<E> implements Callable<ResultBean> {private static Logger logger = LoggerFactory.getLogger(HandleCallable.class); // 线程名称private String threadName = "";private Map<String, Object> params;// 具体执⾏任务private ITask<ResultBean<String>, E> task;public HandleCallable(String threadName, List<E> data, Map<String, Object> params, ITask<ResultBean<String>, E> task) {this.threadName = threadName;this.data = data;this.params = params;this.task = task;}@Overridepublic ResultBean<List<ResultBean<String>>> call() throws Exception {// 该线程中所有数据处理返回结果ResultBean<List<ResultBean<String>>> resultBean = ResultBean.newInstance();if (data != null && data.size() > 0) {("线程:{},共处理:{}个数据,开始处理......", threadName, data.size());// 返回结果集List<ResultBean<String>> resultList = new ArrayList<>();// 循环处理每个数据for (int i = 0; i < data.size(); i++) {// 需要执⾏的数据E e = data.get(i);// 将数据执⾏结果加⼊到结果集中resultList.add(task.execute(e, params));("线程:{},第{}个数据,处理完成", threadName, (i + 1));}("线程:{},共处理:{}个数据,处理完成......", threadName, data.size()); resultBean.setData(resultList);}return resultBean;}}View CodeMultiThreadUtils类: 多线程⼯具类package mon.multi.execute;import java.util.ArrayList;import java.util.List;import java.util.Map;import pletionService;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorCompletionService;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import mon.model.ResultBean;/***** MultiThreadUtils<BR>* 创建⼈:wangbeidou <BR>* 时间:2018年8⽉8⽇-下午8:20:42 <BR>* @version 2.0**/public class MultiThreadUtils<T> {private static Logger logger = LoggerFactory.getLogger(MultiThreadUtils.class);// 线程个数,如不赋值,默认为5private int threadCount = 5;// 具体业务任务private ITask<ResultBean<String>, T> task;// 线程池管理器private CompletionService<ResultBean> pool = null;/**** 初始化线程池和线程个数<BR>* ⽅法名:newInstance<BR>* @return MultiThreadUtils<BR>* @exception <BR>* @since 2.0*/public static MultiThreadUtils newInstance(int threadCount) {MultiThreadUtils instance = new MultiThreadUtils();threadCount = threadCount;instance.setThreadCount(threadCount);return instance;}/**** 多线程分批执⾏list中的任务<BR>* ⽅法名:execute<BR>* 创建⼈:wangbeidou <BR>* 时间:2018年8⽉8⽇-下午8:22:31 <BR>* @param data 线程处理的⼤数据量list* @param params 处理数据是辅助参数传递* @param task 具体执⾏业务的任务接⼝* @return ResultBean<BR>* @exception <BR>* @since 2.0*/@SuppressWarnings("rawtypes")public ResultBean execute(List<T> data, Map<String, Object> params, ITask<ResultBean<String>, T> task) { // 创建线程池ExecutorService threadpool = Executors.newFixedThreadPool(threadCount);// 根据线程池初始化线程池管理器pool = new ExecutorCompletionService<ResultBean>(threadpool);// 开始时间(ms)long l = System.currentTimeMillis();// 数据量⼤⼩int length = data.size();// 每个线程处理的数据个数int taskCount = length / threadCount;// 划分每个线程调⽤的数据for (int i = 0; i < threadCount; i++) {// 每个线程任务数据listList<T> subData = null;if (i == (threadCount - 1)) {subData = data.subList(i * taskCount, length);} else {subData = data.subList(i * taskCount, (i + 1) * taskCount);}// 将数据分配给各个线程HandleCallable execute = new HandleCallable<T>(String.valueOf(i), subData, params, task);// 将线程加⼊到线程池pool.submit(execute);}// 总的返回结果集List<ResultBean<String>> result = new ArrayList<>();for (int i = 0; i < threadCount; i++) {// 每个线程处理结果集ResultBean<List<ResultBean<String>>> threadResult;try {threadResult = pool.take().get();result.addAll(threadResult.getData());} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}}// 关闭线程池threadpool.shutdownNow();// 执⾏结束时间long end_l = System.currentTimeMillis();("总耗时:{}ms", (end_l - l));return ResultBean.newInstance().setData(result);}public int getThreadCount() {return threadCount;}public void setThreadCount(int threadCount) {this.threadCount = threadCount;View Code测试类TestTaskpackage mon.multi.execute;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import mon.model.ResultBean;/**** 具体执⾏业务任务需要实现ITask接⼝在execute中重写业务逻辑* TestTask<BR>* 创建⼈:wangbeidou <BR>* 时间:2018年8⽉8⽇-下午8:40:32 <BR>* @version 2.0**/public class TestTask implements ITask<ResultBean<String>, Integer> {@Overridepublic ResultBean execute(Integer e, Map<String, Object> params) {/*** 具体业务逻辑:将list中的元素加上辅助参数中的数据返回*/int addNum = Integer.valueOf(String.valueOf(params.get("addNum")));e = e + addNum;ResultBean<String> resultBean = ResultBean.newInstance();resultBean.setData(e.toString());return resultBean;}public static void main(String[] args) {// 需要多线程处理的⼤量数据listList<Integer> data = new ArrayList<>(10000);for(int i = 0; i < 10000; i ++){data.add(i + 1);}// 创建多线程处理任务MultiThreadUtils<Integer> threadUtils = MultiThreadUtils.newInstance(5);ITask<ResultBean<String>, Integer> task = new TestTask();// 辅助参数加数Map<String, Object> params = new HashMap<>();params.put("addNum", 4);// 执⾏多线程处理,并返回处理结果ResultBean<List<ResultBean<String>>> resultBean = threadUtils.execute(data, params, task); }}。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

大数据处理之Java线程池使用前言:最近在做分布式海量数据处理项目,使用到了java的线程池,所以搜集了一些资料对它的使用做了一下总结和探究,前面介绍的东西大多都是从网上搜集整理而来。

文中最核心的东西在于后面两节无界队列线程池和有界队列线程池的实例使用以及线上问题处理方案。

1. 为什么要用线程池?在Java中,如果每当一个请求到达就创建一个新线程,开销是相当大的。

在实际使用中,每个请求创建新线程的服务器在创建和销毁线程上花费的时间和消耗的系统资源,甚至可能要比花在实际处理实际的用户请求的时间和资源要多的多。

除了创建和销毁线程的开销之外,活动的线程也需要消耗系统资源。

如果在一个JVM中创建太多的线程,可能会导致系统由于过度消耗内存或者“切换过度”而导致系统资源不足。

为了防止资源不足,服务器应用程序需要一些办法来限制任何给定时刻处理的请求数目,尽可能减少创建和销毁线程的次数,特别是一些资源耗费比较大的线程的创建和销毁,尽量利用已有对象来进行服务,这就是“池化资源”技术产生的原因。

线程池主要用来解决线程生命周期开销问题和资源不足问题,通过对多个任务重用线程,线程创建的开销被分摊到多个任务上了,而且由于在请求到达时线程已经存在,所以消除了创建所带来的延迟。

这样,就可以立即请求服务,使应用程序响应更快。

另外,通过适当的调整线程池中的线程数据可以防止出现资源不足的情况。

网上找来的这段话,清晰的描述了为什么要使用线程池,使用线程池有哪些好处。

工程项目中使用线程池的场景比比皆是。

本文关注的重点是如何在实战中来使用好线程池这一技术,来满足海量数据大并发用户请求的场景。

2. ThreadPoolExecutor类Java中的线程池技术主要用的是ThreadPoolExecutor 这个类。

先来看这个类的构造函数,ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)corePoolSize 线程池维护线程的最少数量maximumPoolSize 线程池维护线程的最大数量keepAliveTime 线程池维护线程所允许的空闲时间workQueue 任务队列,用来存放我们所定义的任务处理线程threadFactory 线程创建工厂handler 线程池对拒绝任务的处理策略ThreadPoolExecutor 将根据 corePoolSize和 maximumPoolSize 设置的边界自动调整池大小。

当新任务在方法execute(Runnable) 中提交时,如果运行的线程少于 corePoolSize,则创建新线程来处理请求,即使其他辅助线程是空闲的。

如果运行的线程多于 corePoolSize 而少于 maximumPoolSize,则仅当队列满时才创建新线程。

如果设置的corePoolSize 和 maximumPoolSize 相同,则创建了固定大小的线程池。

ThreadPoolExecutor是Executors类的实现,Executors类里面提供了一些静态工厂,生成一些常用的线程池,主要有以下几个:newSingleThreadExecutor:创建一个单线程的线程池。

这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。

如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。

此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

newFixedThreadPool:创建固定大小的线程池。

每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。

线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。

newCachedThreadPool:创建一个可缓存的线程池。

如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。

此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。

在实际的项目中,我们会使用得到比较多的是newFixedThreadPool,创建固定大小的线程池,但是这个方法在真实的线上环境中还是会有很多问题,这个将会在下面一节中详细讲到。

当任务源源不断的过来,而我们的系统又处理不过来的时候,我们要采取的策略是拒绝服务。

RejectedExecutionHandler接口提供了拒绝任务处理的自定义方法的机会。

在ThreadPoolExecutor中已经包含四种处理策略。

1)CallerRunsPolicy:线程调用运行该任务的 execute 本身。

此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。

public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) {r.run();}}这个策略显然不想放弃执行任务。

但是由于池中已经没有任何资源了,那么就直接使用调用该execute的线程本身来执行。

2)AbortPolicy:处理程序遭到拒绝将抛出运行时RejectedExecutionExceptionpublic void rejectedExecution(Runnable r, ThreadPoolExecutor e) { throw new RejectedExecutionException();}这种策略直接抛出异常,丢弃任务。

3)DiscardPolicy:不能执行的任务将被删除public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {} 这种策略和AbortPolicy几乎一样,也是丢弃任务,只不过他不抛出异常。

4)DiscardOldestPolicy:如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序(如果再次失败,则重复此过程)public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) {e.getQueue().poll();e.execute(r);}该策略就稍微复杂一些,在pool没有关闭的前提下首先丢掉缓存在队列中的最早的任务,然后重新尝试运行该任务。

这个策略需要适当小心。

3. ThreadPoolExecutor无界队列使用public class ThreadPool {private final static String poolName = "mypool";static private ThreadPool threadFixedPool = new ThreadPool(2);private ExecutorService executor;static public ThreadPool getFixedInstance() {return threadFixedPool;}private ThreadPool(int num) {executor = Executors.newFixedThreadPool(num, new DaemonThreadFactory(poolName));}public void execute(Runnable r) {executor.execute(r);}public static void main(String[] params) {class MyRunnable implements Runnable {public void run() {System.out.println("OK!");try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}for (int i = 0; i &lt;10; i ) {ThreadPool.getFixedInstance().execute(new MyRunnable());}try {Thread.sleep(2000);System.out.println("Process end.");} catch (InterruptedException e) {e.printStackTrace();}}}在这段代码中,我们发现我们用到了Executors.newFixedThreadPool()函数,这个函数的实现是这样子的:return new ThreadPoolExecutor(nThreads, nThreads, 0L,LISECONDS,new LinkedBlockingQueue());它实际上是创建了一个无界队列的固定大小的线程池。

执行这段代码,我们发现所有的任务都正常处理了。

但是在真实的线上环境中会存在这样的一个问题,前端的用户请求源源不断的过来,后端的处理线程如果处理时间变长,无法快速的将用户请求处理完返回结果给前端,那么任务队列中将堵塞大量的请求。

这些请求在前端都是有超时时间设置的,假设请求是通过套接字过来,当我们的后端处理进程处理完一个请求后,从队列中拿下一个任务,发现这个任务的套接字已经无效了,这是因为在用户端已经超时,将套接字建立的连接关闭了。

这样一来我们这边的处理程序再去读取套接字时,就会发生I/0 Exception. 恶性循环,导致我们所有的处理服务线程读的都是超时的套接字,所有的请求过来都抛I/O异常,这样等于我们整个系统都挂掉了,已经无法对外提供正常的服务了。

对于海量数据的处理,现在业界都是采用集群系统来进行处理,当请求的数量不断加大的时候,我们可以通过增加处理节点,反正现在硬件设备相对便宜。

但是要保证系统的可靠性和稳定性,在程序方面我们还是可以进一步的优化的,我们下一节要讲述的就是针对线上出现的这类问题的一种处理策略。

4. ThreadPoolExecutor有界队列使用public class ThreadPool {private final static String poolName = "mypool";static private ThreadPool threadFixedPool = null;public ArrayBlockingQueue queue = new ArrayBlockingQueue(2);private ExecutorService executor;static public ThreadPool getFixedInstance() {return threadFixedPool;}private ThreadPool(int num) {executor = new ThreadPoolExecutor(2, 4,60,TimeUnit.SECONDS, queue,new DaemonThreadFactory(poolName), new ThreadPoolExecutor.AbortPolicy());}public void execute(Runnable r) {executor.execute(r);}public static void main(String[] params) {class MyRunnable implements Runnable {public void run() {System.out.println("OK!");try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}}int count = 0;for (int i = 0; i &lt;10; i ) {try {ThreadPool.getFixedInstance().execute(new MyRunnable());} catch (RejectedExecutionException e) {e.printStackTrace();count ;}}try {("queue size:"ThreadPool.getFixedInstance().queue.size());Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Reject task: " count);}}首先我们来看下这段代码几个重要的参数,corePoolSize 为2,maximumPoolSize为4,任务队列大小为2,每个任务平均处理时间为10ms,一共有10个并发任务。

相关文档
最新文档