JavaEE 多线程详细讲解(2)

1.线程不安全分析

(1)线程不安全的主要原因就是,系统的抢占式执行,对于内核设计者来说,这是非常方便的一个执行方式,但是这却却导致线程不安全的问题,也有不抢占执行的系统,但是这种系统会导致你的系统性能不是特别好。

(2)多个线程执行操作一个对象不会发生线程不安全的情况

(3)String之所以设置成无法改变,也是为了线程安全,如果想改可以试一试反射 

(4)为了更好的解决线程不安全问题,我们可以将非原子操作改成原子操作这个月就可以更安全的保证线程的安全

2.锁

2.1锁的定义

(1)锁可以理解成,解锁,上锁这个操作,拿到锁以后,就可以使你的线程互斥,只有这个线程搞完然后释放锁,然后需要的线程拿到锁以后才能继续执行后序的操作。

 (2)在一个程序中可以有多把锁,只有对一个非原子事物进行加锁才会发生互斥这个情况

图解

2.2锁的简单总结

2.3锁的具体实现(代码)

(1)创建一个类型(Object)由于Object类是所有类的父类所以所有类都可以拿到以Object枷锁的锁。(这种设定是不太合理的)

在python中,以及c++中能够加锁的是非常少的。

(2)锁的格式

这个锁是同步的,同步的反义词就是独占

(3)锁的注意事项

 (4)在使用sychronized方法,进入到了大括号中,就是加锁了,当这个大括号中的运行结束以后,就会自动的解锁(其他的语言也是这样的)

2.4锁的互斥

如果两个线程对对同一个对象进行加锁就会发生互斥,对两个不同的对象进行加锁就不会发生互斥。

(1)代码(互斥)

这种情况就是两个线程同时用一把锁对线程进行加锁,这时候就会发生互斥,程序会直接终止 

(2)代码(不互斥)

用两把锁对其进行加锁这时候就可以避免互斥了

 2.5图集锁的互斥

 这个拿到锁的过程可以理解为我约会一个女生这个女生同意了这个时候女生就是被我上锁了,这时候要是其他男生来就会被阻塞,约会不了

2.6代码实例

(1)代码

package thread;


class Counter {
    private int count = 0;

    synchronized public void add() {
        count++;
    }

    public static void func() {
        synchronized (Counter.class) {
            // ....
        }
    }


    public int get() {
        return count;
    }
}

    public class Demo20 {
        public static void main(String[] args) throws InterruptedException {
            Counter counter = new Counter();
            Counter counter2 = new Counter();
            // Object locker = new Object();

            Thread t1 = new Thread(() -> {
                for (int i = 0; i < 50000; i++) {
                    // counter.add();
                    counter.func();
                }
            });
            Thread t2 = new Thread(() -> {
                for (int i = 0; i < 50000; i++) {
                    // counter2.add();
                    counter2.func();
                }
            });
            t1.start();
            t2.start();
            t1.join();
            t2.join();
            System.out.println("count = " + counter.get());
        }
}

我们可以用counter这个类来进行加锁,对于java来说锁只是一个标准,只要加锁的对象是一样的就行了。

其中我们也可以用this来进行加锁,这个方法也是不错的相当于简化()直接在括号里面写一个this。

3.锁的扩展用法

(1)针对类的类对象进行加锁

(2)通过反射来拿到当作锁的类的信息并进行加锁,类似于加锁继承

其中我们要注意的就是如果在多个线程对这个func方法进行调用这时候就会发生锁竞争。 

(3)解决方式 加锁这个func中的方法,当这个锁使用这个方法的时候相当于是this这个对象在使用func中的方法的这个对象,这时候就不会发生锁的竞争。

2.5锁的嵌套 

(4)对对象加锁使用对象中的方法发生锁竞争的情况。

(5)我们也可以使用静态方法来进行加锁实现,但是我并不是很推荐

4.锁的要记住的东西

3.死锁问题的出现?

3.1小练习来判断这个代码是否有问题(可能有问题也是算的)

(1)

这种写法也会可能出现问题,两个线程可能发生的问题有,t1执行完毕了,但是t2还在执行,这时候就会变成串行执行

 (2)

这串代码乍一眼看上去是没毛病,但是其实他是有问题的,for循环中的i的值会被锁锁住,所以可能会出现下面的情况,{t1在执行的过程中,t2已经执行完毕了这时候t2的i就会把t1的i给覆盖这时候就会出现问题}

(3)特殊情况(可重入锁)

3.2synchronized为什么这么智能不会被死锁? 

(1)

   当一个线程已经获得了锁并再次请求同一个锁时,JVM不会立即释放第一个锁再重新获取。相反,它会继续持有这个锁,而不会导致阻塞。这种情况被称为重入锁。因此,即使同一个线程多次请求同一个锁,它也不会释放锁再重新获取,而是继续持有锁。

另一方面,如果一个线程尝试获取一个已经被其他线程持有的锁,那么它将被阻塞,直到锁可用。这种行为是由JVM的线程调度器和对象监视器来管理的。

3.3可重入锁的作用

可重入锁相当于保护你的这个线程的安全如果用了这个线程以外的锁就会将这个锁进行阻塞,这样可以更好的保证你的线程安全

4.死锁会出现的3个场景

(1)

(2)场景而就是有两个线程,两把不同的锁,两个线程分别需要另一个线程解锁释放的锁才能执行下一步这时候就会发生死锁

(3)第三个场景就是第二个场景的升级版本 

代码

5.小知识 

1.如果需要查看哪个线程需要哪一把锁我们可以用idea中自带的软件来查找这个线程是持有的哪一把锁。画圆圈的就是这些线程获取到的锁以及这个线程的状态是什么也可以找到。

2.死锁发生的条件必须要背下来的小知识(必须要背下来)

3.多个线程要用锁的时候只需要将所得顺序约定好然后挨个加锁就行了(大致提一下后序会详细讲解)

5.引起线程不安全的主要原因 

(1)内存的可见性是可能使得线程发生线程的不安全问题。

     接下来我会写一段代码来对这种情况来进行详细的讲解。

两个线程分别是用来读和写的,但是我们会发现输入的是0但是却没有将线程1给停止。

接下来我会用图解的形式给大家详细的讲解

(2)首先我要先给大家讲解一个东西,当一个计算机对一个数据进行读取的或者比较的时候是三个操作的。

(3)load先从内存中读取数据到cpu寄存器中

(4)cmp(比较,同时会产生跳转)条件成立的时候就会继续顺序执行,条件不成立的时候就会跳转到另一个地址上面来进行执行。

(5)其中我们要注意在循环中这种操作的速度是非常快的,短时间会出现大量的load和cmp反复执行的效果

而且load执行消耗的时间会比cmp多很多!!

多个几千倍,上万倍!!

(6)在上面代码的过程中,load的速度非常慢,执行一次load消耗的时间顶成千上万倍的load的次数

(7)另外JVM还会每次发现load的执行结果是一样的,(为空),这时候JVM就会直接把load的操作直接优化了,读取到的结果将会是空。所以这就会使得循环不会被终止(相当于裁员)

(8)其中要注意的就是IO操作注定是反复hi下的结果是不相同的,所以IO操作是不会被优化掉的,IO操作是在load然后cmp之后的操作。

4.解决方式

关键字(volatile)只要用这个关键字进行修饰就让JVM知道这一部分是不需要进行优化的。

(有些人想既然不优化的化不会发生这种事情那么,JVM干嘛要进行优化,给大家举一个简单的例子,如果进行优化了,那么这个线程将会比以前的速度快十倍多)

6.线程饿死wait关键字

我们用wait关键字就代表着

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/607188.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

从心理学角度看,GPT 对人有什么影响?

开启个性化AI体验&#xff1a;深入了解GPT的无限可能 导言 GPT 与我们日常生活的融合标志着技术进步的重大飞跃&#xff0c;为提高效率和创新提供了前所未有的机遇。然而&#xff0c;当我们与这些智能系统日益紧密地交织在一起时&#xff0c;探索它们对个人产生的细微的心理影响…

15-LINUX--线程的创建与同步

一.线程 1.线程的概念 线程是进程内部的一条执行序列或执行路径&#xff0c;一个进程可以包含多条线程。 2.线程的三种实现方式 ◼ 内核级线程&#xff1a;由内核创建&#xff0c;创建开销大&#xff0c;内核能感知到线程的存在 ◼ 用户级线程&#xff1a;线程的创建有用户空…

抖音APP运用的AI技术拆解

1.推荐系统&#xff08;RS&#xff09; 用户画像&#xff1a;根据用户的信息&#xff08;如地区、性别、年龄、收藏、关注......&#xff09;进行分析&#xff0c;构建用户画像&#xff0c;对用户进行分类&#xff1b; 行为分析&#xff1a;将用户的显形行为数据&#xff08;如…

PaddleOCR使用

最近在项目过程中需要用到文字识别的能力&#xff0c;之前没有接触过。需要对现有的开源能力进行调研和学习。 1. 基本概念 1.1 PaddlePaddle PaddlePaddle 是一个由百度开源&#xff0c;基于 Python 的深度学习框架。PaddlePaddle 针对不同的硬件环境提供了不同的安装包或安…

2024/5/9 QTday4

完成定时器制作 #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);connect(&timer2, &QTimer::timeout, this, &Widget::label_begin);connect(&…

Linux0.11中MINIX 文件系统

阅读linux 的源码的时候对minix 文件系统有很多的疑惑&#xff0c;根据自己的认识将这些做一个总结。 MINIX 文件系统由六个部分组成&#xff0c;分别是引导块&#xff0c;超级块&#xff0c;i结点位图&#xff0c;逻辑块位图&#xff0c;i结点&#xff0c;数据块。 引导块&am…

Python 中 “yield“ 的不同行为

在我们使用Python编译过程中&#xff0c;yield 关键字用于定义生成器函数&#xff0c;它的作用是将函数变成一个生成器&#xff0c;可以迭代产生值。yield 的行为在不同的情况下会有不同的效果和用途。 1、问题背景 在 Python 中&#xff0c;“yield” 是一种生成器&#xff0…

【Pytorch】1.读取训练数据集

导入Dataset类 from torch.utils.data import Dataset # 注意是Dataset&#xff08;大写&#xff09;的才是类通过jupyter我们可以阅读一下Dataset类的具体使用方法 help(Dataset) # 或者直接 Dataset??我们可以看到具体对Dataset类的解释 从蓝色字体我们可以得出 所有的代…

鸿蒙开发-ArkTS语言-容器-非线性容器

鸿蒙开发-UI-web 鸿蒙开发-UI-web-页面 鸿蒙开发-ArkTS语言-基础类库 鸿蒙开发-ArkTS语言-并发 鸿蒙开发-ArkTS语言-并发-案例 鸿蒙开发-ArkTS语言-容器 文章目录 前言 一、非线性容器 1.HashMap 2.HashSet 3.TreeMap 4.TreeSet 5.LightWeightMap 6.LightWeightSet 7.P…

vue uniapp 小程序 判断日期是今天(显示时分秒)、昨天、本周的周几、超出本周显示年月日

效果图&#xff1a; util.js /*** 转换时间*/ const messageFormat (datetime) >{ let result "";let currentTime new Date();if(isToday(datetime)){result datetime.substring(11,16);}else if(isYesterday(datetime)){result "昨天";}else if(…

EasyExcel导出带自定义下拉框数据的Excel模板

文章目录 前言&#x1f4dd;一、导入依赖二、创建导出工具1.创建模板实体类2.创建自定义注解3.添加动态选择接口4.EasyExcelUtil工具类 三、导出、导入Excel接口1.导出接口2.导入接口3.导出结果 总结 前言&#x1f4dd; 在项目中导入excel时需要通过下拉框选择值传入&#xff…

解决在Outlook中预定Teams会议不显示入会链接的问题

今天遇到一个很蛋疼的teams问题&#xff0c;花了点时间才解决。本来以为是很简单的问题&#xff0c;随便网上冲浪一下就能找到答案的&#xff0c;结果根本就没有好的解决方案&#xff0c;所以我分享出来希望后来的老哥少走点弯路。 问题描述 简单来说&#xff0c;就是在Outlo…

Pytorch入门—Tensors张量的学习

Tensors张量的学习 张量是一种特殊的数据结构&#xff0c;与数组和矩阵非常相似。在PyTorch中&#xff0c;我们使用张量来编码模型的输入和输出&#xff0c;以及模型的参数。 张量类似于NumPy的ndarrays&#xff0c;只是张量可以在GPU或其他硬件加速器上运行。事实上&#xf…

IntelliJ IDEA 配置JDK

IntelliJ IDEA-之配置JDK 我们的开发神器IDEA安装好了之后&#xff0c;在实际开发中&#xff0c;我们如何去配置好JDK的版本呢&#xff1f; 注意&#xff1a;需要保证JDK在已经成功安装的情况下&#xff0c;再进行IDEA的配置 现在就行动&#xff0c;让IntelliJ IDEA成为你征…

Windows系统使用powershell批量移动特定起始位置的“快捷方式”

移动特定起始位置的“快捷方式” 快捷方式都对应一个的目标和“起始位置”&#xff0c;现在想要把特定起始位置的快捷方式移动到一个文件夹中。 新建文本文档&#xff0c;输入如下内容&#xff1a; # 设置变量 $oldPath "D:\111\111_1" $newPath "D:\111\1…

C语言—操作符详解(操作符、进制转换、原码反码补码、结构体)

1.操作符分类 算术操作符&#xff1a; 、- 、 * 、 / 、%移位操作符&#xff1a;<< >> //移动的是二进制位位操作符&#xff1a;& | ^ //使用二进制位进行计算赋值操作符&#…

前端js面试题--从字符串中删除删除注释代码

问题&#xff1a;从字符串中删除删除注释代码 描述&#xff1a; solution(weex,rex # and react\nflutter\nnative ssss !hybrid app, [#, !]) 写一个solution函数清除后面参数数组里面的字符串 打印效果 代码1 思路&#xff1a; 将字符全凡是有去掉标志符号的全部添加\n…

Ubuntu20.4中复现Graspness

Ubuntu20.4中复现Graspness 文章目录 Ubuntu20.4中复现Graspness1.安装cuda和cudnn2.安装pytorch3.安装MinkowskiEngine4.编译graspnetAPI5. RuntimeError: "floor" "_vml_cpu" not implemented for IntRefernece &#x1f680;非常重要的环境配置&#x1…

pyqt 分组框控件QGroupBox

pyqt 分组框控件QGroupBox 分组框控件QGroupBox介绍效果代码 分组框控件QGroupBox介绍 QGroupBox提供了一个框架&#xff0c;用于将其他控件&#xff08;如按钮、滑块、标签等&#xff09;组合在一起。 QGroupBox 通常包含一个标题栏和一个内容区域。标题栏显示文本标签&#…

经典回溯算法之N皇后问题

问题描述&#xff1a; 有一个N*N的棋盘&#xff0c;需要将N个皇后放在棋盘上&#xff0c;保证棋盘的每一行每一列每一左斜列每一右斜列都最多只能有一个皇后。 按照国际象棋的规则&#xff0c;皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如…