Java 并发编程
线程状态
new --> runnable <---> running --> dead
| ^
| |
*---> blocked ---*
| |
| |
*---> waiting ---*
| |
| |
*-> time waiting *
- new 创建状态
- runnable 就绪状态,线程所需资源准备完毕
- running 运行状态,线程获得处理机时间
- blocked 阻塞状态,线程被同步阻塞或者I/O阻塞
- waiting 阻塞状态,线程主动等待
- time waiting 阻塞状态,线程主动睡眠指定时间
- dead 消亡状态,线程执行完毕或异常中断
Thread 类
简单例子
创建一个简单线程的例子如下,重写的 run 方法中为线程执行代码,start 方法启动线程。
new Thread() {
@Override
public void run() {
System.out.println("new thread");
}
}.start();
常用方法
// 线程进入就绪状态
start()
// 线程主动睡眠指定时间
sleep(long millis)
sleep(long millis, int nanoseconds)
// 线程让出处理机时间,给同优先级的线程
// 注意该方法让线程重回就绪状态,而不是阻塞状态
yield()
// 等待线程执行完毕,或者等待指定时间
join()
join(long millis)
join(long millis, int nanoseconds)
// 中断处于阻塞状态的线程,注意不能中断正在运行中的线程
interrupt()
// 获取线程标识符
getID()
// 获取设置线程名称
getName()
setName()
// 获取设置线程优先级
getPriority()
setPriority()
// 设置线程是否为守护线程
setDaemon()
// 判断是否为守护线程
isDaemon()
参考 http://www.importnew.com/26834.html
thread 对比 runnable
参考 https://blog.csdn.net/wwww1988600/article/details/7309070
守护线程
setDaemon(true)
必须在start()
之前设置,否则会抛出IllegalThreadStateException
异常,且不能将运行的线程设置为守护线程- 守护线程中产生的新线程,也是守护线程。
- 守护线程不要访问固有资源(文件、数据库等),因为线程会随时发生中断,不能保证操作的安全性。
参考 https://www.cnblogs.com/lixuan1998/p/6937986.html
线程池
ThreadPoolExecutor 类
构造函数及其参数
该类有四个构造函数,下面是参数最全的构造函数。
ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
- corePoolSize 核心池大小。创建线程池后,线程池中的线程数为0。当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到 corePoolSize 后,就会把到达的任务放到缓存队列当中。
- maximumPoolSize 线程池最大线程数,表示在线程池中最多能创建多少个线程。
- keepAliveTime 线程无任务执行时,最多保持多长时间后终止。只有线程池中的线程数大于 corePoolSize 时,keepAliveTime才会起作用。
- unit 参数 keepAliveTime 的时间单位,有以下7种取值。
TimeUnit.DAYS; //天
TimeUnit.HOURS; //小时
TimeUnit.MINUTES; //分钟
TimeUnit.SECONDS; //秒
TimeUnit.MILLISECONDS; //毫秒
TimeUnit.MICROSECONDS; //微妙
TimeUnit.NANOSECONDS; //纳秒
- workQueue 存储等待执行任务的阻塞队列。
- handler 拒绝处理任务时的策略,有以下4种策略。
ThreadPoolExecutor.AbortPolicy // 丢弃任务,并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy // 丢弃任务,但不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy // 丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy // 由调用线程处理该任务
常用方法
execute() // 向线程池提交任务,交由线程池去执行。
submit() // 向线程池提交任务,与 execute() 方法不同,其能够返回任务执行的结果。
shutdown() // 关闭线程池
shutdownNow() // 关闭线程池
静态方法创建线程池
Executors 类中有几个静态方法,可用于创建配置好的线程池。一般没有特别要求时,推荐使用下面的静态方法创建线程池。
newCachedThreadPool() // 创建容量大小为 Integer.MAX_VALUE 的线程池
newSingleThreadExecutor() // 创建容量大小为 1 的线程池
newFixedThreadPool(int) // 创建容量为指定大小的线程池
参考 https://www.cnblogs.com/dolphin0520/p/3932921.html
注意点
- 线程频繁创建与销毁,会降低执行效率,因而可采用线程池代替。
volatile关键字与synchronize关键字
参考 https://www.cnblogs.com/zhengbin/p/5654805.html
java 锁
参考 https://www.cnblogs.com/wuhan729/p/8601108.html
java内存模型
Java内存模型规定了所有的变量都存储在主内存(Main Memory)中,此外每条线程还有自己的工作内存(Working Memory)。
线程的工作内存中保存了被该线程使用到的变量的主内存副本拷贝,线程对变量的所有操作(读取、赋值等)都必须在工作内存中进行,不能直接读写主内存中的变量。并且,不同的线程之间也无法直接访问对方工作内存中的变量,线程间变量值得传递均需要通过主内存来完成,
参考 http://www.cnblogs.com/zhengbin/p/6407137.html
concurrent包
参考 http://www.importnew.com/26461.html
CAS 原理
CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。 如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值 。否则,处理器不做任何操作。无论哪种情况,它都会在 CAS 指令之前返回该 位置的值。(在 CAS 的一些特殊情况下将仅返回 CAS 是否成功,而不提取当前 值。)CAS 有效地说明了“我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。”
参考 https://www.cnblogs.com/barrywxx/p/8487444.html
参考 https://blog.csdn.net/u011305680/article/details/80187623