线程池的工作原理
1.线程池判断核心线程池里的线程是否都在执行任务。如果不是,则创建一新的工作线程来执行任务。如果核心线程池里的线程都在执行任务,则执行第二步。
2.线程池判断工作队列是否已经满。如果工作队列没有满,则将新提交的任务存储在这个工作队列里进行等待。如果工作队列满了,则执行第三步。
3.线程池判断线程池的线程是否都处于工作状态。如果没有,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和策略来处理这个任务。
构造器中参数含义:
1) corePoolSize
线程池中的核心数。当提交任务后,线程池创建一个新线程执行任务,真到当前线程数等于corePoolSize;如果当前线程数为corePoolSize,继续提交任务被保存到阻塞队列中,等待被执行。
2)maximumPoolSize
线程池中允许的最大线程数。如果当前阻塞队列满了,且继续提交任务,则创建的线程执行任务,前提是当前线程数小于maximumPoolSize;
3)keepAliveTime
线程空闲时的存活时间。默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。但是如果调用了allowCoreThreadTimeOut(boolean)方法,keepAliveTime参数也会起作用,直到线程池中的线程数为0;
4)unit
keepAliveTime参数的时间单位。
例如TimeUnit.DAYS
5)workQueue
任务缓存队列,用来存放等待执行的任务。如果当前线程数为corePoolSize,继续提交的任务就会被保存到任务缓存队列中,等待被执行。
BlockingQueue(阻塞队列)
SynchronousQueue(同步队列)一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态。因此,如果线程池中始终没有空闲线程(任务提交的平均速度快于被处理的速度),可能出现无限制的线程增长。
LinkedBlockingQueue (链接阻止队列):基于链表结构的阻塞对列,如果不设置初始化容量,其容量Integer.MAX_VALUE,即为无界队列。因此,如果线程池中线程数达到了corePoolSize,且始终没有
空闲线程(任务提交的平均速度快于被处理的速度),任务缓存队列可能出现无限制的增长。
ArrayBlockingQueue(数组阻止队列):基于数组结构的有界阻塞队列,按FIFO排序任务
6.threadFactory 线程工厂,创建新线程时使用的线程工厂。
7.handler 任务拒绝策略,当阻塞队列满了,且线程池中的线程数达到maximumPoolSize,如果继续提交任务, 就会采取任务拒绝策略处理该任务,线程池提供了4种任务拒绝策略:
AbortPolicy:丢弃任务并抛出RejectedExecutionException异常,默认策略;
CallerRunsPolicy:由调用execute方法的线程执行该任务;
DiscardPolicy:丢弃任务,但是不抛出异常;
DiscardOldestPolicy:丢弃阻塞队列最前面的任务,然后重新尝试执行任务(重复此过程)。
当然也可以根据应用场景实现RejectedExecutionHandler接口自定义饱和策略,如记录日志或持久 化存储不能处理的任务。
守护线程
正常情况下,非守护线程的执行时间和主线程无关,即使主线程已经结束,也不会影响子线程的运行。
守护线程是为其它线程提供服务的线程
守护进程的特点是当程序中主线程结束时,守护线程会自动中止
如何将一个子线程设置为守护线程
在一个线程调用start启动之前,调用方法thread.setDaemon
(true);就可以将thread线程设置为守护线程.
守护线程一般应该是一个独立的线程,它的run()方法是一个无限
循环
守护线程与其它线程的区别是,如果守护线程是唯一运行着的线程,程序会自动退出
锁
synchronized相对于volatile是重量级的线程安全的方法,可以保证3大特性:原子性、可见性、有序性。
可以将并发操作转换为串型执行
1同步代码块:
2.同步方法(synchronized):在方法上添加同步关键字,当前的锁对象为当前对象no---对象锁。
使用的是对象锁,所以只能new一个对象,才可以得到互斥的效果。如果创建多个则不能达到互斥的目的
3.同步静态方法,以当前类Class对象作为锁---类锁
使用类锁时,不管new了多少个对象,都可以得到互斥的效果。
如果使用不同锁多个线程不会实现互斥效果。
引入锁机制以解决线程安全问题:
悲观锁:当存在多个线程操作共享数据时,需要保证同一时刻有且只有一个线程
在操作共享数据,其他线程必须等到该线程处理完数据后再进行
乐观锁:CAS compare and set
synchronized总结
synchronized同步关键字,用于代码同步处理,解决线程安全问题
synchronized同步方法 以当前对象充当锁
public synchronized void pp(){}
synchronized同步静态方法 以当前类Class充当锁
public synchronized static void pp(){}
synchronized同步代码块 自定义对象充当锁
synchronized(obj){}
synchronized原理
在添加synchronized关键字后就可以保证在一个时刻上只有一个线程在调用某个方法或
者代码块,不会出现并发的情形,达到排队执行的效果。
synchronized能够保证 原子性 可见性 有序性
volatile 原子性 可见性
jdk6之前是重量级锁,JDK6开始优化锁的状态总共有四种,无锁状态(使用乐观锁CAS,没有synchronized)、偏向锁、轻量级锁和质量级锁。锁状态的改变是根据竞争激烈程度进行的,在几乎无竞争的条件下,会使用偏向锁,在轻度竞争的条件下,会由偏向锁升级为轻量级锁,在重度竞争的条件下,会使用偏向锁,在轻度竞争的条件下,会由偏向锁升级为轻量级锁,再升级的重量级锁,但是锁的升级是单向的,也就是说只能从低到高升级,不会出现锁的降级
对象在内存中存储时可以分为对象头、实例数据和对齐