共享模型之管程
1. 共享带来的问题
1.1 小故事
1.2 java的体现
两个线程对初始化值为0的静态变量,一个做自增,一个做自减,各做5000次,结果是0吗?
@Slf4j(topic = "c.Test17")
public class Test17 {
static int count = 0;
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(()->{
for (int i = 0; i < 5000; i++) {
count++;
}
},"t1");
Thread t2 = new Thread(()->{
for (int i = 0; i < 5000; i++) {
count--;
}
},"t2");
t1.start();
t2.start();
t1.join();
t2.join();
log.debug("count:{}",count);
}
}
1.3 问题分析
1.4 临界区
1.5 竞态条件 Race Condition
多个线程在临界区内执行,由于代码的执行序列不同而导致结果无法预测,称之为发生了竞态条件
2. synchronized解决方案
2.1 应用之互斥
2.2 syschronized解决
语法:
synchronized(对象)
{
临界区
}
@Slf4j(topic = "c.Test17")
public class Test17 {
static int count = 0;
static Object room = new Object();
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(()->{
for (int i = 0; i < 5000; i++) {
synchronized (room){
count++;
}
}
},"t1");
Thread t2 = new Thread(()->{
for (int i = 0; i < 5000; i++) {
synchronized (room){
count--;
}
}
},"t2");
t1.start();
t2.start();
t1.join();
t2.join();
log.debug("count:{}",count);
}
}
2.3 syschronized理解
2.4 syschronized思考
3. 方法上的synchronized
3.1 synchronized加在方法上
3.2 “线程八锁”
4. 变量的线程安全分析
4.1 变量安全性?
4.2 局部变量线程安全分析
成员变量例子
执行
局部变量--暴露引用
从这个例子可以看出来private和final提供【安全】的意义所在,请体会开闭原则中的【闭】
4.3 常用线程安全类
4.4 实例分析
5. 习题
卖票,转账
6. Monitor(锁)概念
6.1 java对象头
6.2 原理之Monitor(锁)
6.3 原理之synchronized
6.4 小故事
6.5 synchronized原理进阶
6.5.1 轻量级锁
6.5.2 锁膨胀
6.5.3 自旋优化
6.5.4 偏向锁
6.5.6 锁消除
7. wait 与 notify
7.1 小故事--为什么需要wait
7.2 原理之wait/notify
7.3 API介绍
@Slf4j(topic = "c.TestWaitNotify")
public class TestWaitNotify {
final static Object obj = new Object();
public static void main(String[] args) throws InterruptedException {
new Thread(()->{
synchronized (obj){
log.debug("执行...");
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("其它代码...");
}
},"t1").start();
new Thread(()->{
synchronized (obj){
log.debug("执行...");
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("其它代码...");
}
},"t2").start();
//主线程两秒后执行
sleep(2);
log.debug("唤醒obj上其它线程");
synchronized (obj){
obj.notify();
// obj.notifyAll();
}
}
}
8. wait与notify的正确姿势
8.1 sleep(long n)和wait(long n)的区别
8.2 优化step1-step5
8.3 模式之保护性暂停
https://mp.csdn.net/console/editor/html/108654208
8.4 模式之生产者消费者
https://mp.csdn.net/console/editor/html/108654208
9.park 与unpark
9.1 基本使用
9.2 原理
10. 重新理解线程状态转换
假设已有线程Thread t
11.多把锁
多把不相干的锁
12.活跃性
12.1 死锁
有这样的情况:一个线程需要同时获取多把锁,这时就容易发生死锁。
12.2 定位死锁
检测死锁可以使用jconsole工具,或者使用jps定位进程id,再用jstack定位死锁
12.3 哲学家就餐问题--死锁
12.4 活锁
活锁出现在两个线程相互改变对方的结束条件,最后谁也无法结束。
12.5 饥饿
很多教程中把饥饿定义为,一个线程由于优先级太低,始终得不到CPU调度执行,也不能够结束,饥饿的情况不易演示,读写锁的时候会设计饥饿问题。
13.ReentrantLock
基本语法:
//获取锁
reentrantlock.lock();
try{
//临界区
}finally{
//释放锁
reentrantLock.unlock();
}
13.1 可重入
可重入是指同一个线程如果首次获得了这把锁,那么因为它是这把锁的拥有者,因此有权利再次获取这把锁。如果是不可重入锁,那么第二次获取锁时,自己也会被锁挡住。
reentrantlock.lock() --> reentrantlock.unlock()
13.2 可打断
reentrantlock.lockInterruptibly() --> t1.interrupt()
13.3 锁超时
reentrantlock.tryLock()
reentrantLock.tryLock(1, TimeUnit.SECONDS)
13.4 公平锁
Reentrantlock默认是不公平的
公平:(一般没必要,会降低并发度)
ReentrantLock reentrantLock = new ReentrantLock(false);
13.5 条件变量
13.6 同步模式之顺序控制
https://mp.csdn.net/console/editor/html/108654208
14.小结
申明:内容来自网络,仅供学习使用
https://www.bilibili.com/video/BV1jE411j7uX