共享模型之管程

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.youkuaiyun.com/console/editor/html/108654208
8.4 模式之生产者消费者
https://mp.youkuaiyun.com/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.youkuaiyun.com/console/editor/html/108654208
14.小结


申明:内容来自网络,仅供学习使用
https://www.bilibili.com/video/BV1jE411j7uX
本文深入探讨了多线程环境下共享模型的问题,包括竞态条件、临界区的概念,并详细解析了synchronized关键字的使用及其原理,展示了如何通过Monitor(锁)机制实现线程安全,同时介绍了ReentrantLock的高级特性。
1091

被折叠的 条评论
为什么被折叠?



