线程池存在的原因
线程池分类:线程池执行器、可调度线程池执行器,"分而治之"
ThreadPoolExecutor的三个实现子类:(以下三个子类虽然功能不同但是其实都是利用ThreadPoolExecutor来创建线程池的)
newCachedThreadPool:
创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用他们,并在需要时使用提供的ThreadFactory创建新线程
特征:
1.线程池中数量没有固定,可达到最大值(Integer.MAX.VALUE)
2.线程池中的线程可进行缓存重复利用和回收,回收默认时间为1分钟
3.当线程池中没有可用的线程,会重新创建一个线程
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CacheThreadPoolDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();//创建一个线程池,左侧是该方法的返回值,Executors为接口
for(int i = 0;i<20;i++){
executorService.execute(new Task());//提交线程
}
executorService.shutdown();
}
}
public class Task implements Runnable {
@Override
public void run() {
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) { //不加休眠时间,不会出现20个线程,因为之前用完的线程会重新被调用
// e.printStackTrace();
// }
System.out.println(Thread.currentThread().getName()+" running");
}
}
newFixedThreadPool:创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。在任意点,在大多数nThreads线程会处于处理任务的活动状态,如果在所有线程处于活动状态时提交附加任务,则在 有可用线程之前,附加任务将在队列中等待,如果在关闭前的执行期间由于任务失败而导致任何线程终止 ,那么一个新线程将代替它执行后序的任务。
特征:
1.线程池中的线程处于一定的量,可以很好的控制并发量
2.线程可以重复被使用,在显示关闭之前,都将一直存在
3.超出一定量的线程被 提交时候需要在队列中等待
public class FixedThreadPoolDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(5);
for (int i = 0 ;i<20;i++){
executorService.execute(new Task());
}
executorService.shutdown();
}
}
Task 类如上
newSingleThreadExecutor:
创建一个使用worker线程的Excutor,以无界队列方式来运行该线程(注意:如果因为在关闭前的执行期间出现失败而终止了此单个线程,那么如果需要,一个线程将替代它执行后序任务)。可保证顺序的执行各个任务,并且在任意给定的时间不会有多个线程是活动的。与其他等效的newFixedTreadPool(1)不同,可保证无需重新配置此方法所返回的执行程序即可使用其他的线程
特征:
1.线程池中最多执行一个线程,之后提交的线程活动将会排在队列中依次执行
public class SingleThreadPoolDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
for(int i = 0;i<20;i++){
executorService.execute(new Task());
}
executorService.shutdown();
}
}
Task如上
ScheduledThreadPoolExcutor 可调度线程池 可以实现延迟、定时等,其两个实现子类newScheduledThreadPool、newSingleScheduledThreadPool
newScheduledThreadPool:创建一个线程池,它可安排在给定延迟后运行命令或者定期的执行
特征:
1.线程池中具有指定数量的线程,即便是空线程也将保留
2.可定时或者延迟执行线程活动
newSingleScheduledThreadPool:创建一个单线程执行程序,它科技安排在给定延迟后运行命令或者定期地执行
特征:
1.线程池中最多执行1个线程,之后提交的线程活动将会排在队列中依次执行
2.可定时或者延迟执行线程活动
//DEMO实现延迟三秒
public class ScheduledThreadPoolDemo {
public static void main(String[] args) {
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
System.out.println(System.currentTimeMillis());
scheduledExecutorService.schedule(new Runnable() { //此时使用schedule方法提交线程
@Override
public void run() {
System.out.println("延迟三秒执行");
System.out.println(System.currentTimeMillis());
}
},3, TimeUnit.SECONDS);
scheduledExecutorService.shutdown();
}
}
//demo2实现延迟1秒,每三秒还有继续执行
public class ScheduledThreadPoolDemo2 {
public static void main(String[] args) {
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
System.out.println(System.currentTimeMillis());
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {//调用方法也改变
@Override
public void run() {
System.out.println("1------延迟一秒执行,每三秒执行一次");
System.out.println(System.currentTimeMillis());
}
},1,3, TimeUnit.SECONDS); //参数改变
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("2------延迟一秒执行,每三秒执行一次");
System.out.println(System.currentTimeMillis());
}
},1,3, TimeUnit.SECONDS);
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("3-------延迟一秒执行,每三秒执行一次");
System.out.println(System.currentTimeMillis());
}
},1,3, TimeUnit.SECONDS);
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("4--------延迟一秒执行,每三秒执行一次");
System.out.println(System.currentTimeMillis());
}
},1,3, TimeUnit.SECONDS);
// scheduledExecutorService.shutdown();
}
}
newWorkStealingPool
创建一个带并行级别的线程池,并行级别决定了同一时刻最多有多少个线程在执行,如不传并行级别参数,将默认为当前系统的CPU个数
线程池的生命周期
如果现有线程数大于核心线程池的大小,小于线程池能创建线程的最大个数,则可以继续创建线程
arrayblockingqueue和linkedblockqueue的区别:(重要!!!)
1.队列中锁的实现不同
ArrayBlockingQueue实现的队列中的锁是没有分离的,即生产和消费用的是同一个锁
LinkedBlockingQueue实现的队列中的锁是分离的,即生产者用的是putLock,消费者用的是takeLock
2.队列大小初始化方式不同
ArrayBlockingQueue实现的队列必须指定队列的大小(底层结构为数组)
LinkBlockiingQueue实现的队列中可以不指定队列的大小,但是默认是Inter.MAX_VALUE
第一种拒绝策略比较好,为默认拒绝策略
(执行逻辑------重要!!!)