java多线程的学习笔记-线程池
创建线程的方式,
继承 Thread 类,但是因为java是单继承类,所以这个方式的话不利于拓展,
实现Runnable接口,用的比较多,
实现Callable,Callable本身没有继承Runnable,是一个函数式编程接口。
Callable对象不能作为Thread的Target,需要和FutureTask联合使用。
MyCallable mc = new MyCallable();
FutureTask ft = new FutureTask<>(mc);
之后就可以调用的new Thread(ft).start()启动了,
因为Callable是有返回值的,ft.get()可以得到这个返回值,而且这个方法是阻塞的。
用线程池创建线程,在开发中都是不允许独立创建线程的,必须通过线程池来创建,
常用的自动创建线程池:Executors.newCachedThreadPool()
Executors.newFixedThreadPool()
Executors.newScheduledThreadPool()
Executors.newSingleThreadExecutor()也都是通过 new ThreadPoolExecutor(corePoolSize,maximumPoolSize,KeepAliveTime,TimeUnit,BlockingQueue,ThreadFactory,RejectedExecutionHandler)
这里的构造函数是用的参数最多的一个。
corePoolSize:核心线程池数量,线程池中的线程的数量,负责执行任务,
maximumPoolSize: 最大线程数量,因为有任务队列的存在,所以可以运行的线程数量是大于等于核心线程池数量的
KeepAliveTime:空闲线程可以存活的时间,超过这个时间的会被销毁,
TimeUnit 上面KeepAliveTime的时间单位
BlockingQueue:
我只写了四个
ArrayBlockingQueue:
有界任务队列,基于数组结构的有界阻塞队列,可以设置队列上限值,FIFO原则排序,当需要执行的任务数量大于corePoolSize的时候,超过的任务就会被放到阻塞队列里,就是BlockingQueue。当阻塞队列已满并且线程数达到了maximunPoolSize,就会执行拒绝策略 也就是 当需要执行的线程数 > maximunPoolSiz + ArrayBlockingQueue的初始容量的话 就会执行拒绝策略 。
LinkedBlockingQueue:
基于链表结构的阻塞队列,FIFO原则排序。当前线程运行数没有达到corePoolSize时,有了新的提交任务会新建任务去执行,达到了corePoolSize的时候,申请的任务会放到阻塞队列里面,LinkedBlockingQueue没有最大值线定,所以构造函数种的maximunSize是不生效的,只要超过corePoolSize,就会一直放到阻塞队列里面去,
SynchronousQueue:
它是一种不存储元素的队列,任务不会先放到队列中去等线程来取,而是直接移交给执行的线程,一般maximumSize设置为Integer.MAX_VALUE.要将一个元素放入SynchronousQueue,就需要有另一个线程在等待接收这个元素。若没有线程在等待,并且线程池的当前线程数小于最大值,则ThreadPoolExecutor就会新建一个线程;否则,根据饱和策略,拒绝任务。newCachedThreadPool默认使用的就是这种同步移交队列。吞吐量高于LinkedBlockingQueue。
PriorityBlockingQueue
优先级阻塞队列,根据优先级执行任务,优先级是通过自然排序或者是Comparator定义实现。如果执行的任务没有实现compareable接口重写方法会报错。执行任务顺序就是按照自定义规则来排序的。默认最大长度是11,但是会自动扩容。
后续可能还有补充。
拒绝策略:
CallerRunsPolicy :
没有太看懂
AbortPolicy :
直接抛出异常,不会执行溢出的任务
DiscardPolicy :
丢弃请求的任务
DiscardOldestPolicy :
丢弃等待时间最长的任务,ArraysBlockingQueue和LinkedBlockingQueue是FIFO的,所以会丢弃下一个即将执行的任务,如果和优先级任务队列一起用,会导致任务队列中优先级最高的任务被丢弃。