Java---多线程
1. 并发基础(线程篇)
1.1 java线程状态及线程状态之间的转化
Java线程分成六种状态
new(新建)—runnable(可运行)—terminated(终结)—blocked(阻塞)—waiting(等待)—timed_waiting(有时限等待)
1.2 操作系统层面有5种状态
注:Java中的runnable涵盖就绪、运行、阻塞I/O.
2. 线程池的核心参数(7个核心参数)
Java中的线程池及其实现类ThreadPoolExecutor
2.1 线程池参数介绍
2.2 代码实现
2.3 handler 4种拒绝策略
- AbortPolicy()—抛出异常
- CallerRunsPolicy() — 由main主线程运行,调用者自己执行
- DiscardPolicy() — 直接丢弃掉
- DiscardOldestPolicy() — 等待最久的线程丢弃掉,新submit来的线程留下来
3. sleep与wait方法对比
3.1 异同点
3.2 代码展示
- wait 要和Lock 配合使用,直接用对象调用wait方法会报错。
- 获得对象锁,就不会报错了。
- t1 线程调用wait方法 会释放锁,主线程得到锁。
- sleep 在synchornized里面 不会释放锁。
- t1 线程调用interrupt() 可中断sleep和wait方法,提前唤醒t1线程
4. lock锁与synchronized锁区别
4.1 异同点
两者都具备基本的互斥、同步、可重入锁(加多道锁)功能。Synchornized 用wait 和notify 实现同步,Lock用await和signal实现同步。
4.2 代码实现
- blocked queue 一个双向链表, 使用lock时,需要手动unlock.
链接: lock_阻塞演示. - 公平锁与非公平锁
- lock_条件变量
Condition类: await阻塞放在waiting queue,signal唤醒到blocked queue 阻塞队列
5. volatile 能否保证线程安全
5.1 什么是线程安全
5.2 代码展示
5.2.1 原子性
虽然运行结果是10,当运行很多次 可能会出错。
balance -= 5; 对应Jvm中有多条指令,若两者(多线程)指令交错,会导致出错,如下所示:
5.2.2 可见性
下面案例是不可见性(无限循环)
JIT即时编译器会优化热点代码。
正确修改: static volatile boolean stop = false; 解决可见性问题
5.2.3 有序性
大量的压测试验。
voliate加的x,y位置不一样效果也不一样。
voliate在内存屏障来实现有序性 下面显示正确案例:(voliate变量 要加在最后写的变量上,最先读的变量上,这样才能起到屏障地作用)
6. Java中的悲观锁与乐观锁
6.1 悲观锁与乐观锁区别
上下文切换的概念:运行–阻塞:记录状态与恢复状态
6.2 代码实现
6.2.1 CAS概念:
链接: 什么是java中的CAS?.
用cas(cas提供原子性)共享变量时,需要voliate修饰。(voliate保证可见性),一般要配合使用。
乐观锁展示:(比较并交换)
6.2.2 悲观锁与乐观锁代码实现共享变量线程安全
悲观锁展示:
乐观锁展示:
7. Hashtable 与 ConcurrentHashMap
7.1 Hashtable 与 ConcurrentHashMap概念区别
1 ConcurrentHashMap与HashMap结构很类似,在每个头结点加了一把锁。
7.2 ConcurrentHashMap原理细节
- 如何put一个元素到HashMap中,根据key计算二次hash值,移位再按位与。(移位再按位与目的:并发度为16时,高4位为索引值)。
- 理解ConcuurentHashMap中的capacity 和 factor 与HashMap中的有所区别。
capacity表示要存放的元素的个数,factor只有第一次初始化时用上,以后还是按0.75扩容。 - 扩容细节:一个个的迁移
4. 查询:forwardingNode 标志已经迁移过,get操作时去新的map上获取,并不会阻塞。迁移链表过程中下面2个1 不能是同一个对象。
- put 分三种情况
0-9 正常put
10 号正在迁移,头节点锁被占用,被阻塞
11-15 forwardingNode
8. ThreadLocal
8.1 谈一谈对ThreadLocal的理解
适用场景:连接数据库获取Connection对象时。
多个线程调用工具类时间格式化会报错,没有考虑线程的安全问题,这个时候threadlocal出现了
链接: 讲解ThreadLocal参考视频.
用TreadLocal修饰—时间格式化SimpleDateFormat
把这个操作放在threadlocal中,解决线程的安全问题。
8.2 线程间隔离 与 线程内共享
ThreadLocalMap解决资源的线程间隔离,ThreadLocal解决线性冲突的方法为:开放寻址放。