线程分类
普通线程:主线程创建的所有子线程都是普通线程
守护线程:JVM停止时,抛弃所有守护线程,不执行finally代码块,也不会回收栈
synchronozied
同步方法、同步代码块前必须获取对应的监视器monitor
线程
之间的相互唤醒
属于内存通信
机制,Java中使用notify和wait来实现,并且必须在synchronized语句块内使用
注意: 启动一个线程,应该给
线程命名
,方便监控和排查问题
condition
由于 wait/notify/notifyAll 必须依赖 synchronized,太重不方便使用
可以使用ReentrantLock的condition
,一个锁可以创建多个通信condition
ConditionObject 和 Object 通信方式
wait=await
notify=signal
notifyAll=signalAll
一个 ReentrantLock 可以有多个 ConditionObject
而 synchronized 把 lock 和 condition合并了,一个sync只对应一个condition
并且不要
在lock/condition`上使用 wait/notify/notifyAll
wait 与 sleep
Thread.sleep()与Object.wait()二者都可以暂停
当前线程释放CPU控制权
,主要的区别在于wait()在释放CPU同时,释放了对象锁(监控器monitor)的控制
未取得
锁(必须是synchronized,ReentrantLock也不行)就直接执行wait、notfiy、notifyAll会抛异常
等待队列condition - 监视器monitor
关键点是
条件谓词
,条件谓词涉及状态变量,状态变量由锁保护,所以在测试条件谓词前
需要先持有
锁
永远在循环中使用wait/await
,并且条件是条件谓语,且条件谓词的状态变量用锁保护
每个Java对象有一个监视器monitor
,实现了同步队列
和等待队列
,且二者是相关的, 区别是 sync 的队列是放在 monitor
的object header
中.
参考 reetrantLock 原理, 使用 同步队列
和 等待队列
来实现.


每个Object或者Class都拥有一个monitor
monitor保证每次只能有一个线程能进入这个房间进行访问被保护的数据
进入房间即为acquire monitor
退出房间即为release monitor
否则进入entry set/wait set队列等待抢占资源
这个队列不是真正的排序,而是唤醒所有等待的线程竞争资源(因为是非公平的)
notify/notifyAll
notify
只会唤起一个wait线程,如果存在多个谓词,存在丢失通知信号的问题,如果只有一个条件谓词,性能足够好。如果Lock的条件队列condition有多个,可以使用notify,(但是notify并不会立即释放monitor,而是等同步块结束才释放)
notifyAll
会唤起所有的wait线程,性能不足够好,但是能兼容多个谓词的情况,synchronized的条件队列condition只有一个,但是谓词却又多个,建议使用notifyAll
notify/notifyAll的时候,没有wait的线程,信号就丢失了
interrupt()
线程
没有直接终止
的方法
线程
有中断的协作机制
,协作更合理,留给线程停下手中的动作,然后
再终止
修改线程的中断状态
-> 表示当前线程应该停止
运行,但是当前
线程不会
立即停止
Thread.sleep();
Thread.join();
Object.wait();
以上动作在监听
到线程
的状态位
被置为中断
,会立即抛出InterruptedException
异常
程序应该对线程中断
做出响应,Thread.interrupted()
方法来判断当前线程状态是否
被设置为中断状态
,但是,interrupted()会清空
线程的中断状态,除非想ignored这个中断,否则就需要捕获InterrupedException处理或者使用.interrupt()向上反馈中断
异常的线程终止
-
非interruped的异常,导致线程中断,在ThreadPool的处理方式是
重建
一个线程
阻塞队列 BlockingQueue
在 生产者/消费者
模式中大量使用
take()
如果队列空,会阻塞直到队列有值
put()
如果队列满,会阻塞直到队列有空间
offer()
如果队列满,会快速返回失败状态
共享变量
1. 线程封闭
- ad-hoc
- 栈限制,只在栈内生成对象,不对外逃逸
- 使用threadLocal
2. 线程不可变
- final
网友评论