参考文章:Java中的多线程你只要看这一篇就够了 - Givefine - 博客园
线程的并行和并发
并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。
并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。并发往往在场景中有公用的资源,那么针对这个公用的资源往往产生瓶颈,我们会用TPS或者QPS来反应这个系统的处理能力。
线程安全:多个线程访问同一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他操作,调用这个对象的行为都可以获得正确的结果,那么这个对象就是线程安全的。
线程同步:即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作, 其他线程才能对该内存地址进行操作,而其他线程又处于等待状态,实现线程同步的方法有很多,临界区对象就是其中一种。
Java通过Executors提供四种线程池(from 百度)
newCachedThreadPool——创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool——创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool——创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor——创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
参考文章:Java并发编程:线程池的使用 - Matrix海子 - 博客园
①线程池中的线程初始化
创建线程池后,线程池中没有线程,需要提交任务才会创建线程。
prestartCoreThread():初始化一个核心线程;
prestartAllCoreThreads():初始化所有核心线程
②workQueue,任务缓存队列,用来存放等待执行的任务
workQueue的类型为BlockingQueue<Runnable>,通常可以取下面三种类型:
1)ArrayBlockingQueue:基于数组的先进先出队列,此队列创建时必须指定大小;
2)LinkedBlockingQueue:基于链表的先进先出队列,如果创建时没有指定此队列大小,则默认为Integer.MAX_VALUE;
3)SynchronousQueue:这个队列比较特殊,它不会保存提交的任务,而是将直接新建一个线程来执行新来的任务。
③任务拒绝策略
当线程池的任务缓存队列已满或线程数目达到maximumPoolSize,还有任务来时会采用任务拒绝策略
1)ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
2)ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
3)ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
4)ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
④线程池的关闭
1)shutdown():不会立即终止线程池,而是要等所有任务缓存队列中的任务都执行完后才终止,但再也不会接受新的任务
2)shutdownNow():立即终止线程池,并尝试打断正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务
⑤线程池容量的动态调整
1)setCorePoolSize:设置核心池大小
2)setMaximumPoolSize:设置线程池最大能创建的线程数目大小
参考文章:由浅入深理解Java线程池及线程池的如何使用 - Janti - 博客园
corePoolSize :线程池的核心池大小,在创建线程池之后,线程池默认没有任何线程。
当有任务过来的时候才会去创建创建线程执行任务。换个说法,线程池创建之后,线程池中的线程数为0,当任务过来就会创建一个线程去执行,直到线程数达到corePoolSize之后,就会被到达的任务放在队列中。(注意是到达的任务)。换句更精炼的话:corePoolSize表示允许线程池中允许同时运行的最大线程数。
如果执行了线程池的prestartAllCoreThreads()方法,线程池会提前创建并启动所有核心线程。
maximumPoolSize :线程池允许的最大线程数,他表示最大能创建多少个线程。maximumPoolSize肯定是大于等于corePoolSize。
keepAliveTime :表示线程没有任务时最多保持多久然后停止。默认情况下,只有线程池中线程数大于corePoolSize时,keepAliveTime才会起作用。换句话说,当线程池中的线程数大于corePoolSize,并且一个线程空闲时间达到了keepAliveTime,那么就是shutdown。
Unit:keepAliveTime的单位。
workQueue:一个阻塞队列,用来存储等待执行的任务,当线程池中的线程数超过它的corePoolSize的时候,线程会进入阻塞队列进行阻塞等待。通过workQueue,线程池实现了阻塞功能
threadFactory:线程工厂,用来创建线程。
handler :表示当拒绝处理任务时的策略。
在java doc中,并不提倡我们直接使用ThreadPoolExecutor,而是使用Executors类中提供的几个静态方法来创建线程池:
Executors.newCachedThreadPool(); //创建一个缓冲池,缓冲池容量大小为Integer.MAX_VALUE
Executors.newSingleThreadExecutor(); //创建容量为1的缓冲池
Executors.newFixedThreadPool(int); //创建固定容量大小的缓冲池