1、新热的弊端
是否仍只有以下新线程执行异步任务?
你出局太多了。 新热的弊端如下。
每次新建thread时创建新对象的性能很差。
b .线程缺乏统一管理。 可能无限制地新建线程,可能会相互竞争,可能会过多地消耗系统资源,引起死机或oom。
c .缺乏定时执行、定期执行、线程中断等更多功能。
与new Thread相比,Java提供的四种类型的线程池的好处包括:
a .重用现有线程,减少创建和擦除对象的开销,性能良好。
b .根据项目大小有效控制最大并发线程数,提高系统资源利用率,同时避免资源过度竞争,避免堵塞。
c .提供定时执行、定期执行、单线程、并发数控制等功能。
2、Java线程池
Java通过执行程序提供了四种类型的线程池:
newCachedThreadPool创建一个可缓存的线程池。 如果线程池的长度超过需要处理的长度,请灵活地重用空闲线程,如果无法重用,请创建新线程。
newFixedThreadPool创建了一个固定长度的线程池,用于控制线程的最大并发行数,超出的线程将在队列中等待。
newScheduledThreadPool创建固定长度的线程池,以支持计划和定期任务执行。
newSingleThreadExecutor创建单线程池,只在唯一的工作线程上执行任务,以确保所有任务都按指定顺序(FIFO、LIFO、优先级)执行。
(1) newCachedThreadPool :
创建可缓存的线程池,如果线程池的长度超过处理所需的长度,则灵活回收可用线程;如果无法回收,则创建新线程。 示例代码如下:
线程池无限大,如果在执行第二个任务时完成了第一个任务,则执行第一个任务的线程将被复用,而不是每次创建新线程。
(2) newFixedThreadPool :
创建用于控制线程并发最大数量的固定长度线程池,超出的线程将在队列中等待。 示例代码如下:
线程池大小为3,每个任务输出索引,然后sleep 2是2秒,因此每2秒打印3个数字。
建议根据系统资源设置固定线程池的大小。 例如,Runtime.getRuntime ().availableProcessors )。 可以浏览PreloadDataCache。
(3) newScheduledThreadPool :
创建固定长度的线程池以支持计划和定期任务的执行。 延迟执行示例代码如下:
表示延迟3秒执行。
定期执行示例代码如下:
表示延迟1秒后每3秒执行一次。
方案设计比时间更安全、更强大
(4) newSingleThreadExecutor :
创建单线程线程池,以便只在唯一的工作线程上执行任务,并且所有任务都按指定的顺序(FIFO、LIFO、优先级)执行。 示例代码如下:
依次输出结果,相当于依次执行各个任务。
当前的GUI程序大部分是单线程的。 Android不适合同时执行单线程,例如数据库操作、文件操作、批量安装APP应用程序和批量删除APP应用程序,但可以用于可能影响IO堵塞性和UI线程响应的操作。
线程池角色:
线程池的作用是限制系统中运行的线程数。
根据系统环境情况,可以自动或手动设置线程数,以获得最佳运行结果; 减少了系统资源的浪费,越多系统就会变得拥挤,效率低下。 在线程池中控制线程数,其他线程排队等待。 一个任务执行完成后,从队列中取第一个任务开始执行。 如果队列中没有等待进程,则线程池中的此资源正在等待。 如果需要执行新任务,则可以在线程池中启动正在等待的工作线程,否则将进入队列。
为什么要使用线程池:
1 .减少创建和销毁线程的次数,并重用每个工作线程以执行多个任务。
2 .根据系统的容错能力,可以调整线程池中的工作线线程的数量,以防止服务器因占用过多内存而疲惫不堪(每个线程需要约1MB的内存,线程越多,消耗的线程越多)
Java中线程池的顶部接口是Executor,但严格意义上说,Executor是运行线程的工具,而不是线程池。 真正的线程池接口是ExecutorService。
几个比较重要的类:
ExecutorService :真正的线程池接口。
scheduledexecutorservice :与timer/timertask一样,可以解决需要重复任务的问题。
thread pool executor :执行服务的默认实现。
scheduledthreadpoolexecutor :继承thread pool executor的ScheduledExecutorService接口实现、周期性任务调度的类实现。
配置线程池很复杂,尤其是在线程池原理不清楚的情况下,很可能会放置的线
程池不是较优的,因此在Executors类里面提供了一些静态工厂,生成一些常用的线程池。1.newSingleThreadExecutor
创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
2.newFixedThreadPool
创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。
3.newCachedThreadPool
创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,
那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。
4.newScheduledThreadPool
创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。
实例代码
一、固定大小的线程池,newFixedThreadPool:
输出结果:
改变ExecutorService pool = Executors.newFixedThreadPool(5)中的参数:ExecutorService pool = Executors.newFixedThreadPool(2),输出结果是:
从以上结果可以看出,newFixedThreadPool的参数指定了可以运行的线程的最大数目,超过这个数目的线程加进去以后,不会运行。其次,加入线程池的线程属于托管状态,线程的运行不受加入顺序的影响。
二、单任务线程池,newSingleThreadExecutor:
仅仅是把上述代码中的ExecutorService pool = Executors.newFixedThreadPool(2)改为ExecutorService pool = Executors.newSingleThreadExecutor();
输出结果:
可以看出,每次调用execute方法,其实最后都是调用了thread-1的run方法。
三、可变尺寸的线程池,newCachedThreadPool:
与上面的类似,只是改动下pool的创建方式:ExecutorService pool = Executors.newCachedThreadPool();
输出结果:
这种方式的特点是:可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。
四、延迟连接池,newScheduledThreadPool: