临界区集合索引问题
先看一张图:
executorService.execute 是一个多线程
会出现的问题:在多线程的情况下操作ArrayList的add()方法会出现下标越界
解决问题:
方式1:List list = Collections.synchronizedList(new ArrayList<>());
方式2:使用 Vector
方式3:volatile修饰+互斥锁,比如Synchronized
线程池尽可能的直接使用:ThreadPoolExecutor,灵活的通过不同的构造以及参数进行管控
ThreadPoolExecutor最多7个参数,5个必传
ThreadPoolExecutor相较于Thread同样有自己的状态,线程池状态与线程状态是两个概念
ThreadPoolExecutor使用阻塞队列注意事项:
- 不能往阻塞队列中插入null,会抛出空指针异常。
- 可以访问阻塞队列中的任意元素,调用remove(o)可以将队列之中的特定对象移除,但并不高效,尽量避免使用。
ThreadPoolExecutor使用LinkedBlockingQueue无界的阻塞队列时,maximumPoolSize这个参数是无效的使用这种任务队列模式时,一定要注意你任务提交与处理之间的协调与控制,不然会出现队列中的任务由于无法及时处理导致一直增长,直到最后资源耗尽的问题。
使用无界任务队列,线程池的任务队列可以无限制的添加新的任务,而线程池创建的最大线程数量就是corePoolSize设置的数量,也就是说在这种情况下maximumPoolSize这个参数是无效的,哪怕你的任务队列中缓存了很多未执行的任务,当线程池的线程数达到corePoolSize后,就不会再增加了;若后续有新的任务加入,则直接进入队列等待,当使用这种任务队列模式时,一定要注意你任务提交与处理之间的协调与控制,不然会出现队列中的任务由于无法及时处理导致一直增长,直到最后资源耗尽的问题。
ThreadPoolExecutor使用PriorityBlockingQueue优先任务队列时内部默认使用的是非公平锁
//源码
public PriorityBlockingQueue(int initialCapacity, Comparator<? super E> comparator) {
this.lock = new ReentrantLock(); //默认构造方法-非公平锁`
...//其余代码略`
}
ThreadPoolExecutor使用 延迟队列DelayQueue时注入其中的元素必须实现 java.util.concurrent.Delayed接口。
线程池的注意点
避免任务的堆积(堆积容易产生内存溢出)
避免线程数过多增加(缓存线程池会导致线程数过度增加)
排查线程泄漏(线程已经执行完毕却无法被回收)