并发编程--Executor
我们在传统多线程编程创建线程时常常是创建一些 Runnable 对象,然后创建对应的Thread对象执行它们,但是如果程序需要并发执行大量的任务时,需要为每个任务都创建一个Thread,进行管理,这将会影响程序的执行效率,并且创建线程过多将会使系统负载过重。
在Java 5 之后,并发编程引入看一堆新的启动、调度和管理线程的API。Executor框架便是Java 5 中引入的,其内部使用了线程池机制,它在java.util.cocurrent 包下,通过该框架来控制线程的启动、执行和关闭,可以简化并发编程的操作。因此,在Java 5 之后,通过Executor来启动线程比使用Thread的start方法更好,除了更易管理,效率更好(用线程池实现,节约开销)外。
为什么引入Executor线程池框架
new Thread()的缺点
- 每次new Thread()耗费性能
- 调用new Thread()创建的线程缺乏管理,被称为野线程,而且可以无限制创建,之间相互竞争,会导致过多占用系统资源导致系统瘫痪。
- 不利于扩展,比如如定时执行、定期执行、线程中断
采用线程池的优点
- 重用存在的线程,减少对象创建、消亡的开销,性能佳
- 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞
- 提供定时执行、定期执行、单线程、并发数控制等功能
Executor框架
Executor框架集对线程调度进行了封装,将任务提交和任务执行解耦。它提供了线程生命周期调度的所有方法,打打简化 线程调度和同步的门槛。
Executors
创建线程池:ThreadPool
用到的工具类:Executors
第一种方式
线程池执行任务:void execute(Runnable command)
在执行任务时,会使用线程池中不确定的线程去执行当前任务。线程如果处于空闲状态,就有可能会执行当前任务第二种方式
创建带有缓存的线程池 会创建一定的线程。
在使用线程池去执行任务时,如果当前线程池中由可用线程,则直接执行任务
如果当前线程池中的所有线程都处于非空闲状态,则会创建新的线程。
第三种方式
单线程的线程池,在该线程池中,只有一个线程存在。
第四种方式
线程池中的线程创建在执行任务时,可以定时执行,用到schedule(Runnable command, long delay, TimeUnit unit)
command 需要执行的任务时Runnable的实现类
delay 延迟的时间的数
unit 延迟的时间的单位
这四种方式都是用的Executors中的ThreadFactory简历的线程,下面就以上四个方法做个比较
package org.lanqiao.executor.demo;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPoolDemo {
public static void main(String[] args) {
//ExecutorService es = Executors.newFixedThreadPool(5);
//ExecutorService es = Executors.newCachedThreadPool();
//ExecutorService es = Executors.newSingleThreadExecutor();
ScheduledExecutorService ses = Executors.newScheduledThreadPool(5);
for(int i = 0 ; i < 20 ; i++) {
Runnable run = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
};
ses.schedule(run, 5000, TimeUnit.MILLISECONDS);
}
}
}