PCB状态字段细分,线程安全问题,加锁,synchronized

news2024/9/29 21:30:07

补充:之前的线程休眠 sleep ,参数是以ms作为单位,但是sleep本身就存在一些误差。sleep(1000),不一定是精确在休眠1000ms(线程的调度,也是需要时间的)

sleep(1000)的意思是说该线程在1000ms之后,就快恢复成“就绪状态”,此时只是随时去cpu执行,但是并不是立刻马上就去执行

因为sleep的特性,也诞生了一个特殊的技巧,sleep(0)让线程放弃cpu,准备下一轮的调度(一般后台开发不太涉及到这个东西,yield方法效果是和sleep(0)一样


一、💛  

PCB的状态字段:

就绪状态阻塞状态 是系统设定的状态。Java把这两个状态进行了细分。

NEW:安排了工作,但是还没有执行(类创建好了,但是没开始start),如下图,他还没有开始start.

 

Runnable:可工作的,又分成(1)正在工作的(线程在cpu上运行) (2)线程在这里排队,随时可以进去cpu

TERMINSTED:终止状态 

BLOCKED:因为锁产生的阻塞(一会讲解锁)

WAITING:因为调用wait产生阻塞(不带时间的)(以后讲解)

TIMED_WAITING:因为sleep产生阻塞(带时间的)

 

 


二、💜 

线程安全问题(重点,考点)

线程不安全:是说单线程执行下没有问题,但是多个线程的执行下,就出现问题了。

bug:实际运行效果,和预期效果不一样就可以叫做bug 

count++:本质是分成三个步骤 

1.把内存的数据,加载到cpu的寄存器

2.把寄存器中的数据进行+1

3.把寄存器中的数据写入内存中

而上述操作在两个线程中可能有以下几个问题

原因就是抢占式执行的结果

 

bug1号 

bug2号,这种当然也很典型, 此外这两个线程的调度顺序也是不确定的,两个操作相对顺序也有差异,那么排序情况就有了无数种情况。

1W的循环结果里,在多少次运行,多少次出现覆盖结果,导致运算的中间结果,也被覆盖了,结果一定小于1w,很多代码都涉及线程安全问题,不仅仅是count++。

线程安全的原因:

1.多个线程之间调度顺序是随机的,操作系统使用抢占式,执行的策略来调整线程。和单线程不同的是,多线程喜爱,代码的执行顺序,产生了更多变化,以往只需考虑一个代码在一个固定顺序下执行正确即可,现在要考虑的多线程下,N种执行顺序下,代码执行结果都要正确。(跑的快和跑的对,有时候就是会冲突)

2.多个线程同时修改同一个变量,容易产生线程安全问题(代码的结构)  

一个线程修改一个变量,多个线程,读取同一个变量,多个线程修改,多个变量都是ok的

3.进行的修改,不是“原子性的”(事务里面,看我之前的),如果修改操作按原子方式去完成,此时也不会有线程安全问题,

4.内存可见性,引起的线程安全问题

5.指令重排序,引起的线程安全问题

针对3号的(也是解决线程安全的最主要的操作)解决方法:加锁,相当于把一组操作包装成一个原子的操作(此处这里的原子,则是通过锁进行互斥,我这个线程工作的时候,其他线程无法进行操作。

Java引入了原子操作synchronized关键字(务必会读(辛可肉耐子)会写

写在方法前面(进入方法就进行加锁操作,出了方法就解锁)

synchronized:只要出了代码不管你是return 也好,抛异常也好,都会正常解锁,比一般的什么lock()方便,所以lock()这种东西也不多介绍。

 

class Count{
    public  int count=0;
    synchronized   public  void increase(){
        count++;
    }
}
public  class  Demo {

    public static void main(String[] args) throws InterruptedException {
        Count counter = new Count();
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 5000; i++) {
                counter.increase();
            }
        });
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 5000; i++) {
                counter.increase();
            }
        });
        t1.start();
        t2.start();

        t1.join();       //等待t1执行完毕,之前上一个没写join,但是就算写他也是错的
        t2.join();       //等待t2执行完毕,最后main线程

        System.out.println(counter.count);
    }
}

 

三、💚  

那么来了一个问题,既然要串行化并发执行,那么多线程有存在的必要吗(不还是一个线程完事,去另一个线程吗?

答:有必要,我们看上面那一串代码,我们能知道线程不是只干了count++这一件事啊,我们也有循环,循环不也是我们需要做的吗,for循环并没有加锁,不涉及线程安全问题,for循环操作的变量是栈上的局部变量,两个线程有两个独立的空间,

两个i不是同一个变量,两个线程改不同的变量,当然不需要加锁了!

因此,两个线程,一部分代码串行化执行,有一部分并发式执行,仍然比纯粹的串行效率要高。

synchronized:进行加锁解锁,其实是以对象展开的

⚠️:t1占一次换t2,再换就是t1,不是5000次一直都是t1啥的哈,两个线程是同时执行的

加锁的目的是为了互斥使用资源(互斥的修改变量)

💖💖​​​​​​​💖重点:如果两个线程针对同一个对象加锁,就会出现锁竞争/锁冲突(即会有阻塞现象)

 假如是不同对象则不存在锁竞争,也就不会阻塞,那么数据也会变得不可靠。

  public  void increase(){
        synchronized (this){
        count++;
    }
  synchronized public void increase(){
        count++}
  //这两个式子相同的意思,就是上面的可以更灵活一点,可以写不同对象
class Count{
    public  int count=0;
    private Object locker=new Object();         //另一个对象
    public  void increase() {
        synchronized (this) {
            count++;              
        }
    }
    public  void increase2(){
        synchronized (locker){                //另一个对象,不存在锁竞争
        count++;
            }
        

  }
}
public  class  Demo {

    public static void main(String[] args) throws InterruptedException {
        Count counter = new Count();
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 5000; i++) {
                counter.increase();
            }
        });
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 5000; i++) {
                counter.increase2();
            }
        });
        t1.start();
        t2.start();

        t1.join();       //等待t1执行完毕
        t2.join();       //等待t2执行完毕,最后main线程

        System.out.println(counter.count);
    }
}

像是上述代码,两个对象针对不同对象加锁,此时不存在阻塞等待,也就不会让程序按照串行的方式进行count++,也就仍然会有线程安全问题,既然不阻塞等待,那么也就是说会有刚才那种的覆盖情况

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

js案例:1.简单计算器

目录 一.效果图 二.实现思路 整体思路 ​ 1.关键是dom操作 ​ 2.设置点击事件 3.数据类型的隐式转换和赋值 三.完整代码 一.效果图 二.实现思路 整体思路 1.关键是dom操作 通过 document.getElementById(id) 获取html中的dom元素 每一个html标签都是一个对象&…

如何用看板让你的项目管理更上一层楼

项目管理的核心挑战 项目管理始终是一个充满挑战的领域。在多变的环境中&#xff0c;管理一个项目并确保其成功完成是一项巨大的任务。那么&#xff0c;为什么项目管理会如此复杂呢&#xff1f; 概述项目的复杂性 每一个项目都有其独特性&#xff0c;无论是项目的规模、团队…

centos 7 系统上重启 mysql 时报错 Failed to restart mysqld.service: Unit not found.

在 centos 7 系统上&#xff0c;使用常规命令&#xff1a;systemctl restart mysql 或 service mysqld restart 重启 mysql 时都会报如下错误&#xff1a; Failed to start mysqld.service: Unit not found. 根据所报错误&#xff0c;在网上搜罗了一圈&#xff0c;未果&#x…

跨境电商B2B2C多用户商城快速搭建(java开源+多语言)

跨境电商已经成为一种重要的商业模式。在跨境电商领域&#xff0c;B2B2C多用户商城是一种常见的商业模式&#xff0c;即面向商家和终端消费者的电商模式。这种模式下&#xff0c;多个商家可以在同一个电商平台上销售商品&#xff0c;终端消费者可以在该平台上购买商品。具体搭建…

【图像去噪的扩散滤波】基于线性扩散滤波、边缘增强线性和非线性各向异性滤波的图像去噪研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

React 入门学习

React 入门 一、基本认识1.1、前言1.2、什么是1.3、编译<br>1.4、特点1.5、高效 二、React环境和基本使用2.1、环境搭建2.2、脚手架项目基本使用2.2.1、src2.2.2、public2.2.3、package.json 三、JSX的理解和使用四、模块与模块化, 组件与组件化的理解4.1、模块与组件4.2…

自定义类型——枚举

枚举 1.枚举的定义 枚举顾名思义就是一一列举。将可能的取值一一列举。 比如我们现实生活中&#xff1a; 一周的星期一到星期日是有限的7天&#xff0c;可以一一列举。性别有&#xff1a;男、女、也可以一一列举。月份有12个月&#xff0c;也可以一一列举 像在这些场景中就可…

【数据结构】——栈、队列的相关习题

目录 题型一&#xff08;栈与队列的基本概念&#xff09;题型二&#xff08;栈与队列的综合&#xff09;题型三&#xff08;循环队列的判空与判满&#xff09;题型四&#xff08;循环链表表示队列&#xff09;题型五&#xff08;循环列表的入队和出队&#xff09; 题型一&#…

浅谈对属性描述符__get__、__set__、__delete__的理解

1、属性描述符的基础介绍 1.1 何为属性描述符&#xff1f; 属性描述符是一种Python语言中的特殊对象&#xff0c;用于定义和控制类属性的行为。属性描述符可以通过定义__get__、__set__、__delete__方法来控制属性的读取、赋值和删除操作。 通过使用属性描述符&#xff0c;可…

2.4G芯片做遥控颈部按摩器方案

颈部按摩器很受上班族的欢迎&#xff0c;具有仿真人揉捏按摩效果&#xff0c;多单位力度调节&#xff0c;舒缓因长时间工作紧绷的的肌肉。主控芯片使用宇凡微的2.4g合封芯片。 一、颈部按摩器方案介绍 颈部按摩器方案的工作原理&#xff0c;主要采用电机驱动按摩触头&#xff0…

3.5 C++ 纯虚函数、抽象类 3.6 依赖倒转原则

纯虚函数 class A { public:virtual void print(){cout<<"A"<<endl;}virtual void test()0; //纯虚函数 }; 一个类内有纯虚函数&#xff0c;这个类就叫抽象类&#xff1b; 抽象类不能实例化&#xff1b; <java、python&#xff1a…

掌握最新的测评补单技术,了解速卖通、虾皮平台的风控机制

想要销量好&#xff0c;免不了要进行测评补单的&#xff0c;因为不管对于哪一个平台的新店铺新产品而言&#xff0c;前期只靠自然流量是很难的&#xff0c;速卖通平台也一样&#xff01;那么速卖通平台要如何进行测评补单呢&#xff1f; 市面上有许多不同的测评系统&#xff0c…

uniapp调查问卷评价功能

我本来用的是uniapp官方提供的组件uni-rate组件&#xff0c;但修改成我想要的样式有点麻烦&#xff0c;于是我就自己手写一个&#xff0c;比用组件简单一点&#xff1b; dom结构 <text class"formTit must">请您对本次活动进行评价</text> <view cl…

【word密码】word设置只读,如何取消?

Word文件打开之后发现是只读模式&#xff0c;那么我们如何取消word文档的只读模式呢&#xff1f;今天给大家介绍几种只读模式的取消方法。 属性只读 有些文件可能是在文件属性中添加了只读属性&#xff0c;这种情况&#xff0c;我们只需要点击文件&#xff0c;再次查看文件属…

爬虫012_字典高级操作_查询_修改_添加_删除和清空_遍历---python工作笔记031

然后来看字典高级,首先 打印某个元素 然后打印的时候注意,如果直接打印的值,在字典中没有就报错 这里要注意不能用点访问

集合工具类 Collections:提升集合操作效率

文章目录 多元素添加&#xff1a;addAll 方法随机置换&#xff1a;shuffle 方法自定义对象排序&#xff1a;sort 方法总结 在Java的集合框架中&#xff0c;Collections 是一个包含了许多操作集合的静态方法的工具类。通过使用 Collections 类提供的方法&#xff0c;我们能够更加…

SDU Crypto School - 计算不可区分性1

Encryption: Computational security 1-4 主讲人&#xff1a;李增鹏&#xff08;山东大学&#xff09; 参考教材&#xff1a;Jonathan Katz, Yehuda Lindell, Introduction to Modern Cryptography - Principles and Protocols. 什么是加密 首先&#xff0c;加密方案的目的在于…

【海拥工具】分享200+个关于AI的网站

给大家分享一个学习、摸鱼必备网站&#xff0c;我的好友海拥✘&#xff08;全网粉丝近20万&#xff0c;CSDN 内容合伙人&#xff0c;全栈领域优质创作者&#xff0c;华为云享专家&#xff0c;阿里云专家博主&#xff0c;InfoQ、蓝桥云课签约作者&#xff0c;HDZ核心组成员&…

石子游戏 dfs + 备忘录 JAVA

Alice 和 Bob 用几堆石子在做游戏。一共有偶数堆石子&#xff0c;排成一行&#xff1b;每堆都有 正 整数颗石子&#xff0c;数目为 piles[i] 。 游戏以谁手中的石子最多来决出胜负。石子的 总数 是 奇数 &#xff0c;所以没有平局。 Alice 和 Bob 轮流进行&#xff0c;Alice 先…

ArcGIS Pro基础入门、制图、空间分析、影像分析、三维建模、空间统计分析与建模、python融合、案例应用全流程科研能力提升

目录 第一章 入门篇 GIS理论及ArcGIS Pro基础 第二章 基础篇 ArcGIS数据管理与转换 第三章 数据编辑与查询、拓扑检查 第四章 制图篇 地图符号与版面设计 第五章 空间分析篇 ArcGIS矢量空间分析及应用 第六章 ArcGIS栅格空间分析及应用 第七章 影像篇 遥感影像处理 第八…