多线程--Executor线程池框架
2020-12-13 02:11
标签:入队 延时 ash 处理 extend tps 继承 string 自动 在Java 5之后,并发编程引入了一堆新的启动、调度和管理线程的API。其内部使用了线程池机制,它在java.util.cocurrent 包下,通过该框架来控制线程的启动、执行和关闭,可以简化并发编程的操作。因此,在Java 5之后,通过Executor来启动线程比使用Thread的start方法更好,除了更易管理,效率更好(用线程池实现,节约开销)外,还有关键的一点:有助于避免this逃逸问题——如果我们在构造器中启动一个线程,因为另一个任务可能会在构造器结束之前开始执行,此时可能会访问到初始化了一半的对象用Executor在构造器中。 Executor框架包括:线程池,Executor,Executors,ExecutorService,CompletionService,Future,Callable等。 每次new Thread()耗费性能 重用存在的线程,减少对象创建、消亡的开销,性能佳 通过Executors提供四种线程池,newFixedThreadPool、newCachedThreadPool、newSingleThreadExecutor、newScheduledThreadPool。当我们创建线程池后,如果没有新任务进来的话,默认是没有线程的,提交任务后线程池才会创建新的线程。如果你想创建线程池时就初始化 1.public static ExecutorService newFixedThreadPool(int nThreads) 2.public static ExecutorService newCachedThreadPool() 3.public static ExecutorService newSingleThreadExecutor() 4.public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) 运行结果:总共只会创建5个线程, 开始执行五个线程,当五个线程都处于活动状态,再次提交的任务都会加入队列等到其他线程运行结束,当线程处于空闲状态时会被下一个任务复用 运行结果:可以看出缓存线程池大小是不定值,可以需要创建不同数量的线程,在使用缓存型池时,先查看池中有没有以前创建的线程,如果有,就复用.如果没有,就新建新的线程加入池中,缓存型池子通常用于执行一些生存期很短的异步型任务 schedule(Runnable command,long delay, TimeUnit unit)创建并执行在给定延迟后启用的一次性操作 运行结果和newFixedThreadPool类似,不同的是newScheduledThreadPool是延时一定时间之后才执行 创建并执行一个在给定初始延迟后首次启用的定期操作,后续操作具有给定的周期;也就是将在 initialDelay 后开始执行,然后在initialDelay+period 后执行,接着在 initialDelay + 2 * period 后执行,依此类推 创建并执行一个在给定初始延迟后首次启用的定期操作,随后,在每一次执行终止和下一次执行开始之间都存在给定的延迟 ExecutorService接口继承自Executor接口,它提供了更丰富的实现多线程的方法,比如,ExecutorService提供了关闭自己的方法,以及可为跟踪一个或多个异步任务执行状况而生成 Future 的方法。 可以调用ExecutorService的shutdown()方法来平滑地关闭 ExecutorService,调用该方法后,将导致ExecutorService停止接受任何新的任务且等待已经提交的任务执行完成(已经提交的任务会分两类:一类是已经在执行的,另一类是还没有开始执行的),当所有已经提交的任务执行完毕后将会关闭ExecutorService。因此我们一般用该接口来实现和管理多线程。 ExecutorService的生命周期包括三种状态:运行、关闭、终止。创建后便进入运行状态,当调用了shutdown()方法时,便进入关闭状态,此时意味着ExecutorService不再接受新的任务,但它还在执行已经提交了的任务,当把已经提交了的任务执行完后,便到达终止状态。如果不调用shutdown()方法,ExecutorService会一直处在运行状态(因为执行完任务的线程被放回线程池中,一直处于active状态,所以进程不会退出。),不断接收新的任务,执行新的任务,服务器端一般不需要关闭它,保持一直运行即可。 一旦Runnable任务传递到execute()方法,该方法便会自动在一个线程上执行。下面是是Executor执行Runnable任务的示例代码: 在Java 5之后,任务分两类:一类是实现了Runnable接口的类,一类是实现了Callable接口的类。两者都可以被ExecutorService执行,但是Runnable任务没有返回值,而Callable任务有返回值。并且Callable的call()方法只能通过ExecutorService的submit(Callable task) 方法来执行,并且返回一个 Future,是表示任务等待完成的 Future。 从结果中可以同样可以看出,submit也是首先选择空闲线程来执行任务,如果没有,才会创建新的线程来执行任务。另外,需要注意:如果Future的返回尚未完成,则get()方法会阻塞等待,直到Future完成返回,可以通过调用isDone()方法判断Future是否完成了返回。 自定义线程池,可以用ThreadPoolExecutor类创建,它有多个构造方法来创建线程池,用该类很容易实现自定义的线程池,这里先贴上示例程序: 当线程池池创建的线程数量大于 所有 BlockingQueue 都可用于传输和保持提交的任务。可以使用此队列与池大小进行交互: 如果运行的线程少于 corePoolSize,则 Executor 始终首选添加新的线程,而不进行排队。(如果当前运行的线程小于corePoolSize,则任务根本不会存放,添加到queue中,而是直接抄家伙(thread)开始运行) 如果运行的线程等于或多于 corePoolSize,则 Executor 始终首选将请求加入队列,而不添加新的线程。 如果无法将请求加入队列,则创建新的线程,除非创建此线程超出 maximumPoolSize,在这种情况下,任务将被拒绝。 线程池堵塞队列容量满之后,将会直接新建线程,数量等于 转:https://www.cnblogs.com/fengsehng/p/6048610.html 多线程--Executor线程池框架 标签:入队 延时 ash 处理 extend tps 继承 string 自动 原文地址:https://www.cnblogs.com/jvStarBlog/p/11027392.htmlExecutor的介绍
new Thread()的缺点
调用new Thread()创建的线程缺乏管理,被称为野线程,而且可以无限制创建,之间相互竞争,会导致过多占用系统资源导致系统瘫痪。
不利于扩展,比如如定时执行、定期执行、线程中断采用线程池的优点
可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞
提供定时执行、定期执行、单线程、并发数控制等功能Executors方法介绍
Executors工厂类
corePoolSize
数量的线程的话,线程池提供了以下两个方法:
prestartCoreThread()
: 立即初始化一个线程prestartAllCoreThreads()
:立即初始化corePoolSize
数量的线程
创建固定数目线程的线程池。
创建一个可缓存的线程池,调用execute将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线 程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。
创建一个单线程化的Executor。
创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代Timer类。1.newFixedThreadPool创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。
ExecutorService executorService = Executors.newFixedThreadPool(5);
for (int i = 0; i ) {
Runnable syncRunnable = new Runnable() {
@Override
public void run() {
Log.e(TAG, Thread.currentThread().getName());
}
};
executorService.execute(syncRunnable);
}
2.newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i ) {
Runnable syncRunnable = new Runnable() {
@Override
public void run() {
Log.e(TAG, Thread.currentThread().getName());
}
};
executorService.execute(syncRunnable);
}
3.newScheduledThreadPool创建一个定长线程池,支持定时及周期性任务执行
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);
for (int i = 0; i ) {
Runnable syncRunnable = new Runnable() {
@Override
public void run() {
Log.e(TAG, Thread.currentThread().getName());
}
};
executorService.schedule(syncRunnable, 5000, TimeUnit.MILLISECONDS);
}
scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnitunit)
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);
Runnable syncRunnable = new Runnable() {
@Override
public void run() {
Log.e(TAG, Thread.currentThread().getName());
}
};
executorService.scheduleAtFixedRate(syncRunnable, 5000, 3000, TimeUnit.MILLISECONDS);
scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);
Runnable syncRunnable = new Runnable() {
@Override
public void run() {
Log.e(TAG, Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
executorService.scheduleWithFixedDelay(syncRunnable, 5000, 3000, TimeUnit.MILLISECONDS);
4.newSingleThreadExecutor创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行
ExecutorService executorService = Executors.newSingleThreadExecutor();
for (int i = 0; i ) {
Runnable syncRunnable = new Runnable() {
@Override
public void run() {
Log.e(TAG, Thread.currentThread().getName());
}
};
executorService.execute(syncRunnable);
}
ExecutorService
ExecutorService是一个接口,ExecutorService接口继承了Executor接口,定义了一些生命周期的方法。
public interface ExecutorService extends Executor {
void shutdown();//顺次地关闭ExecutorService,停止接收新的任务,等待所有已经提交的任务执行完毕之后,关闭ExecutorService
List
Executor执行Runnable任务
public class TestCachedThreadPool{
public static void main(String[] args){
ExecutorService executorService = Executors.newCachedThreadPool();
// ExecutorService executorService = Executors.newFixedThreadPool(5);
// ExecutorService executorService = Executors.newSingleThreadExecutor();
for (int i = 0; i ){
executorService.execute(new TestRunnable());
System.out.println("************* a" + i + " *************");
}
executorService.shutdown();
}
}
class TestRunnable implements Runnable{
public void run(){
System.out.println(Thread.currentThread().getName() + "线程被调用了。");
}
}
Executor执行Callable任务
下面给出一个Executor执行Callable任务的示例代码:
public class CallableDemo{
public static void main(String[] args){
ExecutorService executorService = Executors.newCachedThreadPool();
List
自定义线程池
public class ThreadPoolTest{
public static void main(String[] args){
//创建等待队列
BlockingQueue
BlockingQueue:阻塞队列
corePoolSize
后,新来的任务将会加入到堵塞队列(workQueue)中等待有空闲线程来执行。workQueue的类型为BlockingQueue,通常可以取下面三种类型:
Integer.MAX_VALUE
maximumPoolSize
后,将会执行任务拒绝策略不在接受任务,有以下四种拒绝策略: