并发
一、什么是线程安全?
对于类或者程序,如果每次调用的运行结果是确定且正确的,那么就是线程安全的。
二、线程安全程序,特别注意的对象是?
共享且可变 的数据
三、对象是否线程安全,看哪几方面?
- 互斥
- 内存可见
四、如何编写线程安全对象?
- 不共享 1、ThreadLocal限制,每个线程都有一份copy
- 不变化 final修饰
- 同步限制: 找数据;读写同步
五、如何线程安全地使用线程不安全的对象?
- 当成局部变量使用
- 作为同步容器中元素使用
- 使用static修饰,jvm会保证同步
- 监视器属性,做一个线程安全地外套
六、代码中,什么是线程?
代码中,线程用一个对象去表示,Thread的实例
七、如何启动线程?
- new Thread
- Executor
八、如何中断线程?
取消、停止线程,中断是最合理的方式
对中断的理解:它并不会真正中断一个正在运行的线程,只是发出中断请求,然后由线程在下一个合适的时刻中断自己
方法:thread.interrupt()
中断原则:线程只能由所有者中断,所有者可以将线程的中断策略封装到合适的取消机制中,例如关闭(shutdown)方法
九、同步锁使用时可能出现问题?
1、死锁
解决或者避免死锁的问题主要在程序员,jvm也提供一些办法
- 一个程序尽量只使用一个锁,使用新锁时,最好将之前的锁释放
- 确定锁使用顺序原则,同样几个锁,保证使用顺序相同
2、饥饿
Java程序对线程的优先级使用不当;持有锁时执行一些无法结束的结构
程序员尽量不要改变线程优先级。因为一旦改变优先级,程序行为就和平台相关。
十、性能
- 低延迟 响应快、执行速率高
- 高吞吐 少的资源办多的事情
- 可伸缩 增加资源,可以办更多事情;减少资源,正常办少的事情
是不是增加并发就一定可以提高吞吐率?
当然不是。 1、线程间切换开销比较大 2、程序中,总会有很多需要串行部分
所以,独占资源锁,既会影响延迟、又是影响可伸缩的主要威胁!
那么,如何降低锁的竞争程序?
- 减少锁的持有时间
- 减小锁的粒度
-
public synchronized void getUser() {......}; public synchronized void getCar() {......}; // 改成 // 用独立的锁,保护独立的状态 // 因为用一个相同锁,会增大串行 public void getUser() { synchronized (users) {......} } public void getCar() { synchronized (cars) {......} }
- 使用分段锁, 如ConcurrrentHashMap,不是锁整个容器而是锁容器的部分
// 不是在整个buckets上用锁 // 而是在每个buckets节点链上用独立的锁 // 降低了锁竞争 public class XMap { private final Object[] locks; private final Node[] buckets; public Object get(object key) { int hash = hash(key); synchronized (locks[hash]) { ....... } }
二、开发线程安全的程序,有哪些基本策略?
- 设计线程安全类
- 明晰不变性规则 因为无状态、状态不变的程序一定是线程安全的
- 改变状态时要求是原子操作 如先检查不存在后新建、a++
- 把所有的可变状态封装在对象内部,通过对象内置锁确保同步
三、有哪些常见需要线程同步的地方?
- 复合操作 比如,先检查再操作
- 多处对同一可变且共享变量的访问 为了保证某个线程改变该变量,对其他线程可见
四、常用的同步方法?
- synchronized 使对象的某个方法同步