1、并行(parallellism)和并发(concurrency)
QQ和微信同时运行,是并行。在微信上和多个人聊天,是并发。
并行是指同一时刻同时做多件事情,并发是指同一时间间隔内做多件事情。
并发编程的目标是充分的利用处理器的每一个核,以达到最高的处理性能。
2、进程(process)和线程(thread)
线程状态:
线程方法join(),wait(),sleep(),yield()区别:
sleep 和wait比较:1.sleep来之Thread,wait来之Object; 2.sleep不释放锁,wait释放锁; 3.sleep不让出系统资源,wait让出系统资源进入线程等待池,需要用notify/notifyall唤醒才能进入就绪; 4.wait只能在同步代码块/方法中用,sleep可以用于任何地方。
sleep和yield:1.yield暂时交出cpu控制权,从running状态转入runnable状态,扔有可能被调度。sleep是进入阻塞状态,时间到即可运行。2.sleep会给其他线程运行机会,不管优先级,yield只给优先级比自己高或相同的线程机会。
sleep:使线程休眠一段时间,时间结束后进入可执行状态,等待调度执行。休眠期间不释放锁
wait:是线程休眠一段时间,若设置参数,时间到自动进入可执行状态,若没有设置参数,需要用notify/notifyall唤醒,wait进入线程等待池,释放锁。
join:当前运行线程可以调用另一个线程的join,当前线程转入阻塞,直到另一个线程运行结束,它才恢复运行。
yield:线程进入就绪状态,不释放锁。
多线程实现方式:
1.继承Thread类(单继承)
package com.thread.create; /** * 模拟龟兔赛跑 * 1.创建多线程:继承Thread * 2.重写run * @author chen * */ public class TestThread { public static void main(String[] args) { Rabbit rabbit = new Rabbit(); Tortoise tortoise = new Tortoise(); rabbit.start(); tortoise.start(); } } class Rabbit extends Thread{ @Override public void run() { for (int i=0;i<100;i++) { System.out.println("兔子跑"+i+"步"); } } } class Tortoise extends Thread{ @Override public void run() { for (int i=0;i<100;i++) { System.out.println("乌龟跑"+i+"步"); } } }2.实现runnalbe接口(多实现,使用静态代理模式)
package com.thread.create; /** * 推荐使用runnable接口创建多线程 * 1.避免单线程局限性 * 2.便于共享资源 * * 使用runnable 创建线程 * 1.类实现runnable接口 +重写run()方法 -->静态代理中的真实角色类 * 2.启动多线程,使用静态代理 * 1)创建真实角色 * 2)创建代理角色+真实角色引用 * 3)调用.start() 启动多线程 * @author chen * */ public class TestRunnable { public static void main(String[] args) { // 1)创建真实角色 Programmer pro = new Programmer(); // 2)创建代理角色+真实角色引用 Thread myproxy = new Thread(pro); // 3)调用.start() 启动多线程 myproxy.start(); //第二条线程 for (int i=0;i<100;i++) { System.out.println("一边聊天。。。。。。"); } //测试共享资源 new Thread(new Web12306(),"黄牛1").start(); new Thread(new Web12306(),"黄牛2").start(); } } class Programmer implements Runnable{ @Override public void run() { for (int i=0;i<100;i++) { System.out.println("一边敲代码。。。。。。"); } } } //方便共享资源实例 class Web12306 implements Runnable{ private int num = 50; @Override public void run() { while(true) { if (num<=0) { break;//跳出循环 } System.out.println(Thread.currentThread().getName()+"抢到了"+num--); } } }3.实现callable接口:
package com.thread.create; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; /** * 使用callable实现多线程 * 优点:可以获取返回值,可以对外抛异常(runnable只能try,catch) * 缺点:创建线程比较繁琐 * 1.创建callable实现类+重写call() * 2.借助执行任务调度服务ExecutorService获取Futrue对象 * ExecutorService service = Executors.newFixedThreadPool(2); Future result = service.submit(实现类对象); 3.获取result.get() 4.停止服务service.shutdownNow(); * 模拟龟兔晒跑 * @author chen * */ public class TestCallable { public static void main(String[] args) throws InterruptedException, ExecutionException { Race tortoise = new Race("乌龟",100); Race rabblit = new Race("兔子",1); //创建线程 ExecutorService service = Executors.newFixedThreadPool(2); //获取值 Future resulTortoise = service.submit(tortoise); Future resultRabbit = service.submit(rabblit); Thread.sleep(5000); //设置跑多少秒 tortoise.setFlag(false); rabblit.setFlag(false); int tortoiseNum= (int) resulTortoise.get(); int rabbitNum= (int) resultRabbit.get(); System.out.println("乌龟跑了:"+tortoiseNum); System.out.println("兔子跑了:"+rabbitNum); //停止服务 service.shutdownNow(); } } class Race implements Callable<Integer>{ private String name; private long time; private boolean flag = true; private int step = 0; public Race(String name) { super(); this.name = name; } public Race(String name, int time) { super(); this.name = name; this.time = time; } public Race() { } @Override public Integer call() throws Exception { while(flag) { Thread.sleep(time); //延时 step++; } return step; } public String getName() { return name; } public void setName(String name) { this.name = name; } public long getTime() { return time; } public void setTime(int time) { this.time = time; } public boolean isFlag() { return flag; } public void setFlag(boolean flag) { this.flag = flag; } public int getStep() { return step; } public void setStep(int step) { this.step = step; } }线程info方法:
package com.thread.create; /** * 1.isAlive()判断线程是否还活着 * 2.getPriority()获得线程优先级 * 3.setPriority()设置线程优先级 * 4.getName()获得线程名字 * 5.currentThread()获取当前运行的进程 * * @author chen * */ public class ThreadInfo { public static void main(String[] args) throws InterruptedException { myThread t1 = new myThread(); Thread proxy = new Thread(t1,"线程1"); proxy.start(); Thread.sleep(100); t1.stop(); } } class myThread implements Runnable{ private boolean flag = true; private int num = 0; @Override public void run() { while(flag) { System.out.println(Thread.currentThread().getName()+"-->"+ num++); } } public void stop() { this.flag = false; } }线程同步:确保并发线程安全(内存安装)synchronized关键字(同步块,同步方法)
难点:锁定范围过大影响性能,过小可能达不到效果。
过多同步可能造成死锁。
生产者消费者问题(有限缓存问题):解决多线程死锁的一个方法
问题:要保证生产者不会在缓存区满的时候加入数据,消费者也不会在缓存区空的时候消费数据。
通常方法有:信号灯法,管程法
package com.thread.create; public class TestProduct_Consumer { public static void main(String[] args) { Movie movie = new Movie(); Play play = new Play(movie); Watch watch = new Watch(movie); new Thread(play).start(); new Thread(watch).start(); } } //共同的资源 class Movie{ private String pic; //信号灯 flag=true,生产者生产,消费者等待;生产完成后通知消费者 。flag = false 生产者等待,消费者消费,消费完成后通知生产者 boolean flag = true; public synchronized void play(String pic) throws InterruptedException { if (!flag) { //生产者等待 this.wait(); } //开始生产 Thread.sleep(500); this.pic = pic; System.out.println("生产了--》"+pic); //生产完成,通知消费 this.notifyAll(); flag = false; } public synchronized void watch() throws InterruptedException { if (flag) { //消费者等待 this.wait(); } //开始消费 Thread.sleep(200); System.out.println("消费了--》"+pic); //通知生产 this.notifyAll(); flag = true; } } //生产者 class Play implements Runnable{ private Movie movie; @Override public void run() { for (int i = 0;i<100;i++) { if (0==i%2) { try { movie.play("左青龙"); } catch (InterruptedException e) { e.printStackTrace(); } }else { try { movie.play("右白虎"); } catch (InterruptedException e) { e.printStackTrace(); } } } } public Play(Movie movie) { super(); this.movie = movie; } } //消费者 class Watch implements Runnable{ private Movie movie; @Override public void run() { for (int i = 0;i<100;i++) { try { movie.watch(); } catch (InterruptedException e) { e.printStackTrace(); } } } public Watch(Movie movie) { super(); this.movie = movie; } }4.任务调度
Timer定时器类:实现定时功能(每隔一段时间触发一次线程)
TimerTask任务类:是一个抽象类,该类实现了runnable接口,因此有多线程的功能。
通过Timer,TimerTask(Spring的任务调度就是通过他们来实现的)
通过继承TimerTask获得多线程能力,将代码写入run()方法,通过Timer类启动多线程。
package com.thread.create; import java.util.Date; import java.util.Timer; import java.util.TimerTask; public class TestTimerTask { public static void main(String[] args) { Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { System.out.println("so easy..."); } }, new Date(System.currentTimeMillis()+1000),100); } }
5.线程池
线程池的概念: 线程池就是首先创建一些线程,它们的集合称为线程池。使用线程池可以很好地提高性能,线程池在系统启动时即创建大量空闲的线程,程序将一个任务传给线程池,线程池就会启动一条线程来执行这个任务,执行结束以后,该线程并不会死亡,而是再次返回线程池中成为空闲状态,等待执行下一个任务。
线程池的工作机制 : 在线程池的编程模式下,任务是提交给整个线程池,而不是直接提交给某个线程,线程池在拿到任务后,就在内部寻找是否有空闲的线程,如果有,则将任务交给某个空闲的线程。 一个线程同时只能执行一个任务,但可以同时向一个线程池提交多个任务。
使用线程池的原因: 多线程运行时间,系统不断的启动和关闭新线程,成本非常高,会过渡消耗系统资源,以及过渡切换线程的危险,从而可能导致系统资源的崩溃。这时,线程池就是最好的选择了。
线程池实现的4种方式(返回值都是ExecutorService, ExecutorService是Java提供的用于管理线程池的类。该类的作用是控制线程数量和重用线程):
(1):Executors.newCacheThreadPool():可缓存线程池,先查看池中有没有以前建立的线程,如果有,就直接使用。如果没有,就建一个新的线程加入池中,缓存型池子通常用于执行一些生存期很短的异步型任务。
package com.thread.create; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPool { public static void main(String[] args) throws InterruptedException { //创建一个可缓存线程 ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); for (int i=0;i<10;i++) { //sleep可明显看到使用的是线程池里面以前的线程,没有创建新的线程 Thread.sleep(1000); cachedThreadPool.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+"在被执行"); } }); } } }线程池为无限大,当执行当前任务时上一个任务已经完成,会复用执行上一个任务的线程,而不用每次新建线程。
(2) Executors.newFixedThreadPool(int n):创建一个可重用固定个数的线程池,以共享的无界队列方式来运行这些线程。
package com.thread.create; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPool { public static void main(String[] args) throws InterruptedException { //创建一个可重用固定个数的线程池 ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3); for (int i=0;i<10;i++) { Thread.sleep(1000); fixedThreadPool.execute(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+"在被执行"); } }); } } }定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors()
(3)Executors.newScheduledThreadPool(int n):创建一个定长线程池,支持定时及周期性任务执行。
package com.thread.create; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class ThreadPool { public static void main(String[] args) throws InterruptedException { //创建一个定长线程池,支持定时及周期性任务执行——延迟执行 ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3); for (int i=0;i<10;i++) { //延迟1秒执行 scheduledThreadPool.schedule(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+"在被执行"); } },1,TimeUnit.SECONDS); } } }定期执行示例代码:
package com.thread.create; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class ThreadPool { public static void main(String[] args) throws InterruptedException { //创建一个定长线程池,支持定时及周期性任务执行——延迟执行 ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3); for (int i=0;i<10;i++) { //延迟1秒执行 scheduledThreadPool.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+"在被执行"); } },1,3,TimeUnit.SECONDS); } } }(4)Executors.newSingleThreadExecutor():创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
package com.thread.create; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadPool { public static void main(String[] args) throws InterruptedException { //创建一个单线程化的线程池 ExecutorService singleThreadPool = Executors.newSingleThreadExecutor(); for (int i=0;i<10;i++) { int index = i; //延迟1秒执行 singleThreadPool.execute(new Runnable() { @Override public void run() { //结果依次输出,相当于顺序执行各个任务 System.out.println(Thread.currentThread().getName()+"正在被执行,打印的值是:"+index); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }); } } }(5)自定义线程池
缓冲队列BlockingQueue简介: BlockingQueue是双缓冲队列。BlockingQueue内部使用两条队列,允许两个线程同时向队列一个存储,一个取出操作。在保证并发安全的同时,提高了队列的存取效率。
常用的几种BlockingQueue:
ArrayBlockingQueue(int i):规定大小的BlockingQueue,其构造必须指定大小。其所含的对象是FIFO顺序排序的。
LinkedBlockingQueue()或者(int i):大小不固定的BlockingQueue,若其构造时指定大小,生成的BlockingQueue有大小限制,不指定大小,其大小有Integer.MAX_VALUE来决定。其所含的对象是FIFO顺序排序的。
PriorityBlockingQueue()或者(int i):类似于LinkedBlockingQueue,但是其所含对象的排序不是FIFO,而是依据对象的自然顺序或者构造函数的Comparator决定。
SynchronizedQueue():特殊的BlockingQueue,对其的操作必须是放和取交替完成。
自定义线程池,可以用ThreadPoolExecutor类创建,它有多个构造方法来创建线程池。
常见的构造函数:ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)
package com.thread.create; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class ThreadPool { public static void main(String[] args) throws InterruptedException { // 创建数组型缓冲等待队列 BlockingQueue<Runnable> bq = new ArrayBlockingQueue<>(10); // ThreadPoolExecutor:创建自定义线程池,池中保存的线程数为3,允许最大的线程数为6 ThreadPoolExecutor tpe = new ThreadPoolExecutor(3, 6, 50, TimeUnit.MILLISECONDS, bq); // 创建3个任务 Runnable t1 = new TempThread(); Runnable t2 = new TempThread(); Runnable t3 = new TempThread(); tpe.execute(t1); tpe.execute(t2); tpe.execute(t3); tpe.shutdown(); } } class TempThread implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName() + "正在被执行"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }; } }问题:
线程池使用的是哪种?
1.newCachedThreadPool创建一个可缓存线程池程
查看源码:
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); } public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), threadFactory); }通过ThreadPoolExecutor创建核心线程数为0,最大线程数为 Integer.MAX_VALUE的线程池,并设置keepAliveTime为60秒。
2.newFixedThreadPool 创建一个定长线程池
查看源码:
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); } public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory); }通过ThreadPoolExecutor创建核心线程数为n,最大线程数为n的线程池,并设置BlockingQueue为LinkedBlockingQueue。
3.newScheduledThreadPool 创建一个定长线程池
查看源码:
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize); } public static ScheduledExecutorService newScheduledThreadPool( int corePoolSize, ThreadFactory threadFactory) { return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory); }通过ScheduledThreadPoolExecutor创建线程池,查看ScheduledThreadPoolExecutor源码:
public class ScheduledThreadPoolExecutor extends ThreadPoolExecutor implements ScheduledExecutorService { 。。。。。。 public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue()); } public ScheduledThreadPoolExecutor(int corePoolSize, RejectedExecutionHandler handler) { super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue(), handler); } }继承了ThreadPoolExecutor并实现了ScheduledExecutorService 。构造方法使用父类即ThreadPoolExecutor构造方法。
4.newSingleThreadExecutor 创建一个单线程化的线程池
查看源码:
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); } public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory)); }返回的是new FinalizableDelegatedExecutorService实例,继续看FinalizableDelegatedExecutorService源码:
static class FinalizableDelegatedExecutorService extends DelegatedExecutorService { FinalizableDelegatedExecutorService(ExecutorService executor) { super(executor); } protected void finalize() { super.shutdown(); } }发现1.返回的是父类DelegatedExecutorService的对象,DelegatedExecutorService实现AbstractExecutorService ,而ThreadPoolExecutor 也实现AbstractExecutorService ,因此newSingleThreadExecutor 创建的对象依然和ThreadPoolExecutor 创建的对象一致,相当于走了一个代理类而已。2.拥有finalize()方法,在GC的时候时触发未被使用的线程池关闭。
static class DelegatedExecutorService extends AbstractExecutorService { 。。。。。。 } public class ThreadPoolExecutor extends AbstractExecutorService { 。。。。。。 }
5.ThreadPoolExecutor( //自定义线程
int corePoolSize,//核心池的大小
int maximumPoolSize, //池中允许的最大线程数,这个参数表示了线程池中最多能创建的线程数量
long keepAliveTime, //当线程数大于corePoolSize时,终止前多余的空闲线程等待新任务的最长时间
TimeUnit unit, //keepAliveTime时间单位
BlockingQueue<Runnable> workQueue,//存储还没来得及执行的任务
ThreadFactory threadFactory,//执行程序创建新线程时使用的工厂
RejectedExecutionHandler handler //超出线程范围和队列容量而使执行被阻塞时所使用的处理程序
)
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); }当不传ThreadFactory 时,会默认使用defaultThreadFactory。构造的线程池前缀为pool-xxxxx-thread-1 ,如所示:
static class DefaultThreadFactory implements ThreadFactory { private static final AtomicInteger poolNumber = new AtomicInteger(1); private final ThreadGroup group; private final AtomicInteger threadNumber = new AtomicInteger(1); private final String namePrefix; DefaultThreadFactory() { SecurityManager s = System.getSecurityManager(); group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); namePrefix = "pool-" + poolNumber.getAndIncrement() + "-thread-"; } 。。。。。。 }自定义线程池参数有哪些?
1.corePoolSize:核心线程数
核心线程会一直存活,即使没有任务需要执行当线程数小于核心线程数时,即使有线程空闲,线程池也会优先创建新线程处理设置allowCoreThreadTimeout=true(默认false)时,核心线程会超时关闭2.BlockingQueue:阻塞队列
当核心线程数达到最大时,新任务会放在队列中排队等待执行。
3.maxPoolSize:最大线程数
当线程数>=corePoolSize,且任务队列已满时。线程池会创建新线程来处理任务当线程数=maxPoolSize,且任务队列已满时,线程池会拒绝处理任务而抛出异常(RejectedExecutionHandler)4.keepAliveTime:线程空闲时间
当线程空闲时间达到keepAliveTime时,线程会退出,直到线程数量=corePoolSize如果allowCoreThreadTimeout=true,则会直到线程数量=05.rejectedExecutionHandler:任务拒绝处理器
两种情况会拒绝处理任务: 当线程数已经达到maxPoolSize,且队列已满,会拒绝新任务当线程池被调用shutdown()后,会等待线程池里的任务执行完毕,再shutdown。如果在调用shutdown()和线程池真正shutdown之间提交任务,会拒绝新任务 线程池会调用rejectedExecutionHandler来处理这个任务。如果没有设置默认是AbortPolicy,会抛出异常ThreadPoolExecutor类有几个内部实现类来处理这类情况: AbortPolicy 丢弃任务,抛运行时异常CallerRunsPolicy 执行任务DiscardPolicy 忽视,什么都不会发生DiscardOldestPolicy 从队列中踢出最先进入队列(最后一个执行)的任务实现RejectedExecutionHandler接口,可自定义处理器线程池执行流程?
当线程数小于核心线程数时,创建线程。当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列。当线程数大于等于核心线程数,且任务队列已满 若线程数小于最大线程数,创建线程若线程数等于最大线程数,抛出异常,拒绝任务自定义线程池参数怎么配置?
如何来设置 需要根据几个值来决定 tasks :每秒的任务数,假设为500~1000taskcost:每个任务花费时间,假设为0.1sresponsetime:系统允许容忍的最大响应时间,假设为1s做几个计算 corePoolSize = 每秒需要多少个线程处理? threadcount = tasks/(1/taskcost) =tasks*taskcout = (500~1000)*0.1 = 50~100 个线程。corePoolSize设置应该大于50根据8020原则,如果80%的每秒任务数小于800,那么corePoolSize设置为80即可queueCapacity = (coreSizePool/taskcost)*responsetime 计算可得 queueCapacity = 80/0.1*1 = 80。意思是队列里的线程可以等待1s,超过了的需要新开线程来执行切记不能设置为Integer.MAX_VALUE,这样队列会很大,线程数只会保持在corePoolSize大小,当任务陡增时,不能新开线程来执行,响应时间会随之陡增。maxPoolSize = (max(tasks)- queueCapacity)/(1/taskcost) 计算可得 maxPoolSize = (1000-80)/10 = 92(最大任务数-队列容量)/每个线程每秒处理能力 = 最大线程数rejectedExecutionHandler:根据具体情况来决定,任务不重要可丢弃,任务重要则要利用一些缓冲机制来处理keepAliveTime和allowCoreThreadTimeout采用默认通常能满足以上都是理想值,实际情况下要根据机器性能来决定。如果在未达到最大线程数的情况机器cpu load已经满了,则需要通过升级硬件(呵呵)和优化代码,降低taskcost来处理。