java并发编程--线程池详细介绍与使用

1、为什么要用线程池

频繁创建线程,销毁线程带来的系统开销非常大,线程池为线程生命周期开销问题和资源不足问题提供了解决方案

2、线程池创建示例

public class ThreadPoolDemo {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        LinkedBlockingQueue<Runnable> objects = new LinkedBlockingQueue<>();
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10,20,3L,TimeUnit.SECONDS,objects);
        for (int i = 0; i < 50; i++) {
            threadPoolExecutor.submit(()->{
                try {
                    Thread.sleep(2000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName());
            });
        }
    }
}

3、Future与Callable,FutureTask简单介绍

1)Callable与Runable功能相似,Callable的call有返回值,可以返回给客户端,而Runable没有返回值,一般情况下,Callable与FutureTask一起使用,或者通过线程池的submit方法返回相应的Future

 Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果、设置结果操作。get方法会阻塞,直到任务返回结果

 FutureTask则是一个RunnableFuture,而RunnableFuture实现了Runnbale又实现了Futrue这两个接口

2)Callable示例

public class CallableDemo implements Callable<String> {
    @Override
    public String call() throws Exception {
        return "xuhan";
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CallableDemo callableDemo = new CallableDemo();
        FutureTask<String> stringFutureTask = new FutureTask<>(callableDemo);
        new Thread(stringFutureTask).start();
        System.out.println(stringFutureTask.get());
    }
}

4、线程池的核心组成部分及运行机制

1)核心组成部分:

corePoolSize:核心线程池大小 cSize
maximumPoolSize:线程池最大容量  mSize
keepAliveTime:当线程数量大于核心时,多余的空闲线程在终止之前等待新任务的最大时间。
unit:时间单位
workQueue:工作队列 nWorks
ThreadFactory:线程工厂
handler:拒绝策略

2)运行机制

通过new创建线程池时,除非调用prestartAllCoreThreads方法初始化核心线程,否则此时线程池中有0个线程,即使工作队列中存在多个任务,同样不会执行

假设任务数X
           x <= cSize  只启动x个线程

x >= cSize && x < nWorks + cSize  会启动 <= cSize 个线程 其他的任务就放到工作队列里

x > nWorks + cSize
           x-(nWorks) <= mSize  会启动x-(nWorks)个线程
           x-(nWorks) > mSize   会启动mSize个线程来执行任务,其余的执行相应的拒绝策略

5、线程池拒绝策略

AbortPolicy:该策略直接抛出异常,阻止系统正常工作
CallerRunsPolicy:只要线程池没有关闭,该策略直接在调用者线程中,执行当前被丢弃的任务(叫老板帮你干活)
DiscardPolicy:直接啥事都不干,直接把任务丢弃
DiscardOldestPolicy:丢弃最老的一个请求(任务队列里面的第一个),再尝试提交任务

6、Excutor框架

下面的方法最终都创建了ThreadPoolExecutor
Executors.newCachedThreadPool:创建一个可以根据需要创建新线程的线程池,如果有空闲线程,优先使用空闲的线程
Executors.newFixedThreadPool:创建一个固定大小的线程池,在任何时候,最多只有N个线程在处理任务
Executors.newScheduledThreadPool:能延迟执行、定时执行的线程池
Executors.newWorkStealingPool:工作窃取,使用多个队列来减少竞争
Executors.newSingleThreadExecutor:单一线程的线程次,只会使用唯一一个线程来执行任务,即使提交再多的任务,也都是会放到等待队列里进行等待
Executors.newSingleThreadScheduledExecutor:单线程能延迟执行、定时执行的线程池

7、线程池使用建议(来源于《并发编程原理与实战》)

1)尽量避免使用Executor框架创建线程池

  •  newFixedThreadPool  newSingleThreadExecutor允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。可以在idea中设置jvm参数限定堆内存
  • newCachedThreadPool newScheduledThreadPool允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM,但在这个程序中,即使限定了堆内存,由于创建线程用的内存是系统剩余的内存(电脑内存-系统其它程序占用的内存-已预留的jvm内存),所以会撑爆电脑内存

2) 创建线程池时,核心线程数不要过大

3) 相应的逻辑,发生异常时要处理

  • submit 如果发生异常,不会立即抛出,而是在get的时候,再抛出异常
  • execute 直接抛出异常
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 、5资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值