Java并发编程-线程池原理,三种线程池、i++、线程池的execute()和submit方法的区别

线程池:https://www.bilibili.com/video/BV1YN411o7Lz?from=search&seid=7073118730878150075

一种自增例子i++

这个使用List实现的,查看List中元素个数:
线程方式
在这里插入图片描述
线程池方式
在这里插入图片描述

三种线程池

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
CorePoolSize表示核心线程数
MaximumPoolSize:表示队列满的情况下,最大的线程数
非核心线程数等于Max-Core

Cahced核心线程为0,非核心线程为2的32次方-1个,队列长度为1,只要一个任务放入队列,必须马上取走.
Single核心线程为1,非核心线程为为0,队列长度为2的32次方-1
Fixed核心线程数为n=10,非核心线程数为0,队列长度为2的32次方-1

阿里巴巴为什么不推荐这三种线程池

Cached:最高 CPU 100%,如果有N个任务,并且任务执行时间比较长,他的队列又只能存放一个任务,那么就会对应着创建N个线程,并且CachedThreadPool允许创建2的32次方-1个线程,就会创建非常多的线程,导致CPU 100%运行.
Fixed Single:内存 OOM,当任务过多,就会放到LinkedBlockingQueue中,放不下的时候,会造成内存溢出

自定义一个线程池:

在这里插入图片描述
在31个任务的时候,出现了RejectExecutionException
在这里插入图片描述
在这里插入图片描述

提交优先级和执行优先级

maximumPoolSize : 当队列中存放的任务达到队列容量的时候,当前可以同时运行的线程数量变为最大线程数。
提交优先级:核心线程 队列 非核心线程
执行优先级:核心线程 非核心线程 队列
为什么这么设计?

提交优先级

ThreadPoolExecutor类
execute(Runnable command){
//有三步:小于核心数,进入核心线程
//大于核心线程数,进入队列
//大于核心线程数且队列已满,则进入非核心线程
//如果都已经满了,则进入拒绝策略.
在这里插入图片描述

}
在这里插入图片描述
在这里插入图片描述

拒绝策略:

默认:RejectExecutionException拒绝执行策略
在这里插入图片描述

4.3 执行execute()方法和submit()方法的区别是什么呢?

execute()方法用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功与否;
submit()方法用于提交需要返回值的任务。线程池会返回一个 Future 类型的对象,通过这个 Future 对象可以判断任务是否执行成功,并且可以通过 Future 的 get()方法来获取返回值,get()方法会阻塞当前线程直到任务完成,而使用 get(long timeout,TimeUnit unit)方法则会阻塞当前线程一段时间后立即返回,这时候有可能任务没有执行完。

  1. 异步计算的结果(Future)
    Future 接口以及 Future 接口的实现类 FutureTask 类都可以代表异步计算的结果。

当我们把 Runnable接口 或 Callable 接口 的实现类提交给 ThreadPoolExecutor 或 ScheduledThreadPoolExecutor 执行。(调用 submit() 方法时会返回一个 FutureTask 对象)

4.4 加餐:Callable+ThreadPoolExecutor+submit()+execute()方法示例代码

https://gitee.com/SnailClimb/JavaGuide/blob/master/docs/java/multi-thread/java%E7%BA%BF%E7%A8%8B%E6%B1%A0%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93.md

 ExecutorService 中没有execute()方法
public interface ExecutorService extends Executor {
	<T> Future<T> submit(Callable<T> task);
	<T> Future<T> submit(Runnable task, T result);
	Future<?> submit(Runnable task);
}
Executor只有一个方法execute,这是Executor的全部内容
public interface Executor {

    /**
     * Executes the given command at some time in the future.  The command
     * may execute in a new thread, in a pooled thread, or in the calling
     * thread, at the discretion of the {@code Executor} implementation.
     *
     * @param command the runnable task
     * @throws RejectedExecutionException if this task cannot be
     * accepted for execution
     * @throws NullPointerException if command is null
     */
    void execute(Runnable command);
}
ublic class ThreadPool01 {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
       ExecutorService executor = new ThreadPoolExecutor(5,10,100, TimeUnit.SECONDS,new ArrayBlockingQueue<>(100),new ThreadPoolExecutor.AbortPolicy());
        List<Future<Integer>> futures = new ArrayList<>();
        for(int i=0;i<10;i++){

//            FutureTask<Integer> futureTask = new FutureTask<Integer>(new Callable<Integer>() {
//                @Override
//                public Integer call() throws Exception {
//                    System.out.println(Thread.currentThread().getName()+"执行了");
//                    return 300;
//                }
//            });
            //executor.execute(futureTask);//execute方法没有返回值,execute(Runnable command);
            //提交任务到线程池
            //这里不可以写FutureTask,只能Callable
            Future<Integer> submit = executor.submit(new Callable<Integer>() {
                @Override
                public Integer call() throws Exception {
                    System.out.println(Thread.currentThread().getName() + "执行了");
                    return 300;
                }
            });//

            futures.add(submit);
        }
        for(Future<Integer> future:futures){
            System.out.println(future.get());
        }
        //终止线程池
        executor.shutdown();

        while(!executor.isTerminated()){}
        System.out.println("main come over");
    }
}

七 线程池大小确定

有一个简单并且适用面比较广的公式:

CPU 密集型任务(N+1): 这种任务消耗的主要是 CPU 资源,可以将线程数设置为 N(CPU 核心数)+1,比 CPU 核心数多出来的一个线程是为了防止线程偶发的缺页中断,或者其它原因导致的任务暂停而带来的影响。一旦任务暂停,CPU 就会处于空闲状态,而在这种情况下多出来的一个线程就可以充分利用 CPU 的空闲时间。
I/O 密集型任务(2N): 这种任务应用起来,系统会用大部分的时间来处理 I/O 交互,而线程在处理 I/O 的时间段内不会占用 CPU 来处理,这时就可以将 CPU 交出给其它线程使用。因此在 I/O 密集型任务的应用中,我们可以多配置一些线程,具体的计算方法是 2N。
如何判断是 CPU 密集任务还是 IO 密集任务?

CPU 密集型简单理解就是利用 CPU 计算能力的任务比如你在内存中对大量数据进行排序。单凡涉及到网络读取,文件读取这类都是 IO 密集型,这类任务的特点是 CPU 计算耗费时间相比于等待 IO 操作完成的时间来说很少,大部分时间都花在了等待 IO 操作完成上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值