JAVA基础——多线程(5种实现方式介绍)

    xiaoxiao2023-11-07  143

    一、概念

    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,对其的操作必须是放和取交替完成。

    Executors提供四种线程池,一般都不用Executors提供的线程创建方式,使用ThreadPoolExecutor创建线程池

    自定义线程池,可以用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,则会直到线程数量=0

    5.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来处理。

     

     

     

    最新回复(0)