(三) 共享模型之管程【共享带来的问题】

news/2024/7/5 2:07:54

一、共享带来的问题

1. 临界区

(1)一个程序运行多个线程本身是没有问题的

(2)问题出在多个线程访问共享资源

1️⃣多个线程读共享资源其实也没有问题

2️⃣在多个线程对共享资源读写操作时发送指令交错,就会出现问题

(3)一段代码块内如果存在对共享资源的多线程读写操作,称这段代码块为临界区

2. 竞态条件 Race Condition

多个线程在临界区内执行,由于代码的执行序列不同而导致结果无法预测,称之为发生了竞态条件

二、Synchronized 解决方案(P54)

1. 应用之互斥

为了避免临界区的竞态条件发生,有多种手段可以达到目的。

(1)阻塞式的解决方案:synchronized、Lock

(2)非阻塞式的解决方案:原子变量

synchronized,即俗称的【对象锁】,它采用互斥的方式让同一时刻至多只有一个线程能持有对象锁,其他线程再想获取这个对象锁时就会阻塞住。这样就能保证拥有锁的线程可以安全的执行临界区内的代码,不用担心线程上下文切换。

注意:

虽然 Java 中互斥和同步都可以采用 synchronized 关键字来完成,但有区别:

(1)互斥是保证临界区的竞态条件发生,同一时刻只能有一个线程执行临界区代码。

(2)同步是由于线程执行的先后顺序不同,需要一个线程等待其他线程运行到某个点。

2. synchronized

synchronized(对象) // 线程1, 线程2(blocked)
{
     临界区
}
@Slf4j(topic = "c.Test17")
public class Test17 {
    static int counter = 0;
    static Object lock = new Object();

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 5000; i++) {
                synchronized (lock) {
                    counter++;
                }
            }
        },"t1");

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 5000; i++) {
                synchronized (lock) {
                    counter--;
                }
            }
        },"t2");

        t1.start();
        t2.start();
        t1.join();
        t2.join();
        log.debug("{}",counter);

    }
}

思考:

synchronized 实际是用对象锁保证了临界区内代码的原子性,临界区内的代码对外是不可分割的,不会被线程切换所打断。

3. 面向对象改进

@Slf4j(topic = "c.Test17")
public class Test17 {
    public static void main(String[] args) throws InterruptedException {
        Room room = new Room();
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 5000; i++) {
                room.increment();
            }
        }, "t1");

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 5000; i++) {
                room.decrement();
            }
        }, "t2");

        t1.start();
        t2.start();
        t1.join();
        t2.join();
        log.debug("{}", room.getCounter());
    }
}

class Room {
    private int counter = 0;

    public synchronized void increment() {
        counter++;
    }

    public synchronized void decrement() {
        counter--;
    }

    public synchronized int getCounter() {
        return counter;
    }
}

三、方法上的 synchronized(P59)

(1)普通方法 

(2) 静态方法  

 (3)不加 synchronized 的方法

不加 synchronzied 的方法就好比不遵守规则的人,不去老实排队(好比翻窗户进去的)

四、变量的线程安全分析(P63)

1. 成员变量和静态变量是否线程安全?

(1)如果它们没有共享,则线程安全

(2)如果它们被共享了,根据它们的状态是否能否改变,又分两种期刊

1️⃣如果只有读操作,则线程安全

2️⃣如果有读写操作,则这段代码是临界区,需要考虑线程安全

2. 局部变量是否线程安全?

(1)局部变量是线程安全的

(2)但局部变量引用的对象则未必

1️⃣如果该对象没有逃离方法的作用范围,它是线程安全的

2️⃣如果该对象逃离方法的作用范围,需要考虑线程安全

3. 常见线程安全类

String

包装类(Integer 等)

StringBuffer

Random

Vector

Hashtable

java.util.concurrent 包下的类

这里说它们是线程安全的是指,多个线程调用它们同一个实例的方法时,是线程安全的。也可以理解为:

(1)它们的每个方法是原子的

(2)但注意它们多个方法的组合不是原子

4.1 不可变类线程安全性

String、Integer 等都是不可变类,因为其内部的状态不可以改变,因此它们的方法都是线程安全的。


http://lihuaxi.xjx100.cn/news/207758.html

相关文章

基于vue3/Vue3的组件库

一、项目简介 基于vue3/Vue3的组件库&#xff0c;Vue赏饭吃 二、实现功能 Basic Grid 栅格 Layout 布局 Color 色彩 Font 字体 Button 按钮 Icon 图标 Form Input 输入框 Radio 单选框 Checkbox 多选框 Switch 开关 Table 表格 Select 选择器 AutoComplete 自动…

未来十年的Python前景会是什么样的?

看了一些文章的答案&#xff0c;我觉得的没有一答案是真正的站在10年后角度来讨论这个问题的&#xff0c;讨论的其实都是现在python的现状或问题&#xff0c;我觉得讨论这种问题时&#xff0c;我们一方面要理性分析&#xff0c;另一方面一定要敢于打开脑洞&#xff0c;作为一对…

刷爆力扣之矩阵中的幻方

刷爆力扣之矩阵中的幻方 HELLO&#xff0c;各位看官大大好&#xff0c;我是阿呆 &#x1f648;&#x1f648;&#x1f648; 今天阿呆继续记录下力扣刷题过程&#xff0c;收录在专栏算法中 &#x1f61c;&#x1f61c;&#x1f61c; 该专栏按照不同类别标签进行刷题&#xff0c…

构造函数原型prototype

一、原型prototype 构造函数通过原型分配的函数是所有对象所共享的。 JavaScript规定&#xff0c;每一个构造函数都有一个prototype属性&#xff0c;指向另一个对象&#xff0c;注意这个prototype就是个对象&#xff0c;这个对象的所有属性和方法&#xff0c;都会被构造函数所…

2022-Q3

2022-Q3 2022 年 11 月 30 日 20:02:55 时间过得很快&#xff0c;到新公司已经 7 个月了。 上次写总结还是在 8 月份。 生活 回首向来萧瑟处&#xff0c;归去&#xff0c;也无风雨也无晴。 浑浑噩噩的, 缺少了对生活&#xff0c;工作的追求。 有段时间&#xff0c;陷入了网络…

设计模式:02观察者模式--labview实现

引言 在观察者模式中&#xff0c;一种叫做被观察者的对象维护了观察者对象的集合&#xff0c;当被观察者对象发生改变时候&#xff0c;它会通知观察者。 在被观察者对象所维护的观察者集合中&#xff0c;能够添加或者删除观察者。被观察者状态变化能够传递给观察者。这样观察者…

Postman接口Mock Server服务器设置

目录 一、适用场景 二、设置步骤 2.1.创建一个mock server 2.2.配置mock server 2.3.Mock Servers创建成功一个新的mock地址 2.4.环境变量Environments&#xff1a;生成一个mock server新的环境变量 2.5.项目集Collections&#xff1a;生成一个mock server新的项目集&am…

计算机组成原理习题课第四章-1(唐朔飞)

计算机组成原理习题课第四章-1&#xff08;唐朔飞&#xff09; ✨欢迎关注&#x1f5b1;点赞&#x1f380;收藏⭐留言✒ &#x1f52e;本文由京与旧铺原创&#xff0c;csdn首发&#xff01; &#x1f618;系列专栏&#xff1a;java学习 &#x1f4bb;首发时间&#xff1a;&…