volatile与synchronized

news2024/10/7 18:21:55

文章目录

  • 前言
  • 一、简介
    • volatile
    • synchronized
  • 二、名词解释
      • 可见性
      • 原子性
      • 指令重排
      • 临界区
      • 对象锁
      • 类锁
  • 二、实战使用
      • 1 Volatile可以解决的问题
      • 2 volatile无法解决非原子性操作问题--synchronized
  • 总结


前言

volatile与synchronized 都是java的关键字

  • volatile一般修饰变量,被修饰的变量会及时将计算值刷新回主内存;
  • synchronized 一般作用于 方法, 代码块等,一般分为 对象锁 和 类锁;

一、简介

volatile

  • 能够保证数据可见性
  • 禁止指令重排,在一定程度上保证了多线程情况下的执行顺序,从而保证结果执行正确
  • 不能完全保证多线程情况下的结果正确: 非原子性操作无法保证

synchronized

  • 被synchronized 修饰后,大体分为两种,一种是对象锁,一种是类锁
  • synchronized 可以保证被修饰的部分,一个时间点只有一个线程执行
  • 在多线程情况下,相当于将多线程转为了串行执行,不能完全达到多线程的性能,但是可以通过控制锁的粒度,尽量减少锁的时间;
  • 对象锁,锁住的是实例对象,类锁,锁住的是字节码

二、名词解释

可见性

  • 当写一个 volatile 变量时,JMM 会把该线程本地内存中的变量强制刷新到主内存中去;这个写操作会导致其他线程中的 volatile 变量缓存无效,无效后也就是强制让其他线程再次读取主内存数据,达到了数据被修改后能被其他线程立马感知到,即可见性;

原子性

  • 没错,与事务中的原子性可以认为是等价的;

指令重排

  • jvm为了优化代码运行的一种手段,编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序
  • 举个例子 ABC 三步
int a = 1; // A操作
int b = 2; // B操作
int sum = a + b;// C 操作
System.out.println(sum);

多线程情况下, 可能是ABC 也可能是 BAC,这种指令重排不会影响结果,所以是允许的;

临界区

  • 所谓“临界区”,指的是某一块代码区域,它同一时刻只能由一个线程执行。说人话就是: 被锁 锁住的代码部分;

对象锁

当synchronized 作用于普通方法,代码块,this 的时候,都是对象锁,每个对象实例一把锁,多个对象实例多个锁,多个锁之间没有影响, 那么多个对象实例之间的数据就不应该用对象锁,只适合单个对象;

类锁

当synchronized 作用于静态方法,this.getClass() 的时候,因为每个对象只有一份class,也就是唯一的,所以这种锁,无论你new 多少个对象实例,它们都公用一把锁

二、实战使用

1 Volatile可以解决的问题

public class Volatile可以解决的问题 {

    private boolean flag = true;
//    private volatile boolean flag = true;
    private int num = 0;

    public void write() {
        flag = false;
        System.out.println(Thread.currentThread().getName() + "开始执行.....");
    }

    public void read() {
        System.out.println(Thread.currentThread().getName() + "开始执行.....");
        while (flag) {
            num++;
        }
        System.out.println(Thread.currentThread().getName() + "结束.....");
        System.out.println("跳出循环" + num);
    }


    public static void main(String[] args) throws InterruptedException {

        Volatile可以解决的问题 handle = new Volatile可以解决的问题();
        new Thread(handle::read).start();
        Thread.sleep(2000);
        new Thread(handle::write).start();
    }
}

两个线程运行 第一个线程判断 当 flag 为ture ,就一直执行
第二个线程改变flag 的值,时期变为flase;
如果不使用volatile修饰,那么flag 虽然会被改变,但是由于没有强制刷新会主内存,那么其实第一个线程也感知不到
所以仍然会继续num++ ,不会停止;
解决问题的关键在于,volatile可以强制将线程内部的计算结果,刷新会主内存,并且使其他线程的值失效,不得不再次去主内存获取
出现问题的现象
就是如上代码,.不用volatile修饰的时候,就会导致即使改变了flag 的值,但是第一个线程仍然无法感知到,所以就一直运行,不会结束

2 volatile无法解决非原子性操作问题–synchronized

@Data
public class 多线程问题 implements Runnable {

    public static int num = 0;
    private synchronized void add() {
        for (int i = 0; i < 500; i++) {
            num++;
        }
    }
//    public volatile static int num = 0;
//    private void add() {
//        for (int i = 0; i < 500; i++) {
//            num++;
//        }
//    }

    @Override
    public void run() {
        add();
    }

    public static void main(String[] args) {


        for (int i = 0; i < 10; i++) {
            多线程问题 pro = new 多线程问题();

            Thread thread = new Thread(pro);
            thread.setName("第一个线程");

            Thread thread1 = new Thread(pro);
            thread1.setName("第二个线程");

            thread1.start();
            thread.start();
            while (Thread.activeCount() > 1) {
                Thread.yield();
            }
            System.out.println(num);
        }
    }
}

volatile无法解决的问题

出现问题的现象是,计算结果无法保证,计算错误; i++ 非原子操作
所以需要用类似 synchronized 的锁,解决这类问题

总结

类似于 synchronized 的属于悲观锁,相对性的就是乐观锁;
乐观锁多用于“读多写少“的环境,避免频繁加锁影响性能;而悲观锁多用于”写多读少“的环境,避免频繁失败和重试影响性能。

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

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

相关文章

做了一年csgo搬砖项目,还清所有债务:会赚钱的人都在做这件事 !

前段時间&#xff0c;在网上看到一句话&#xff1a;有什么事情&#xff0c;比窮更可怕&#xff1f; 有人回答说&#xff1a;“又忙又窮。” 很扎心&#xff0c;却是绝大多数人的真实写照。 每天拼死拼活的996&#xff0c;你有算过你的時间值多少钱&#xff1f; 我们来算一笔…

操作系统——死锁

0.关注博主有更多知识 操作系统入门知识合集 目录 5.1死锁概念 5.2死锁的起因 5.3预防死锁的策略 思考题&#xff1a; 5.1死锁概念 在介绍死锁之前&#xff0c;先来探究一个问题&#xff1a;哲学家就餐问题。五个哲学家围坐在圆桌边&#xff0c;有5支筷子&#xff0c;哲…

免费的绘图工具DrowIO下载及安装

还在为论文绘图而烦恼吗&#xff1f;还在为如何选择画图工具而烦恼吗&#xff1f;没事&#xff0c;本期就给你们推荐一款超级好用且免费的绘图工具——DrawIO。 目前使用比较多的绘图工具有&#xff1a;Visio、亿图图示、Word、PPT、DrawIO等 其中DrawIO由于其既实用又免费的…

使用 Esp32 和 TinyML 进行手势分类

介绍 手势分类是机器学习可以做什么的一个简单但同时又很好的例子。它使用大量“混乱”的数据来对事物进行分类。 在这个项目中,我们将制作一个包含 4 个类的分类器,idle、up_down、left_right 和 circle。 数据采集 要将数据上传到 Edge Impulse,我们需要使用 Edge Imp…

199. 二叉树的右视图【111】

难度等级&#xff1a;中等 上一篇算法&#xff1a; 236. 二叉树的最近公共祖先【190】 力扣此题地址&#xff1a; 199. 二叉树的右视图 - 力扣&#xff08;Leetcode&#xff09; 1.题目&#xff1a;199. 二叉树的右视图 给定一个二叉树的 根节点 root&#xff0c;想象自己站在…

JavaScript事件

事件流描述的是从页面接收事件的顺序。比如说单击了某个按钮&#xff0c;但是单击事件不仅发生在按钮上&#xff0c;在单击按钮的同时&#xff0c;也单击了按钮的容器元素&#xff0c;甚至是 <body> 、<html> 、document。 事件传播的顺序不同导致存在两种事件流机…

初识CPU(二)

目录 一、控制器的功能与工作原理 1.控制器的设计思路 2.控制器的分类 3.微程序 3.1微命令 3.2微操作 3.3微指令 3.4微程序 3.5微地址 4.控制方式 4.1同步控制方式 4.2异步控制方式 4.3联合控制方式 4.4人工控制方式 二、微指令 5.微指令的编码方式 5.1直接编码…

基于springboot的家政服务管理平台(源码,设计文档等)

摘要 随着家政服务行业的不断发展&#xff0c;家政服务在现实生活中的使用和普及&#xff0c;家政服务行业成为近年内出现的一个新行业&#xff0c;并且能够成为大众广为认可和接受的行为和选择。设计家政服务管理平台的目的就是借助计算机让复杂的销售操作变简单&#xff0c;…

kafka的安装与使用

文章目录 kafka安装1 上传安装包2 解压安装包3 创建logs文件夹4 修改配置文件5 分发kafka6 启动kafka kafka使用1 启动kafka2 关闭kafka3 查看topic4 创建topic,名称为test5 删除名称为test的topic6 向topic发送数据7 从topic里消费数据 kafka安装 kafka安装前需要确认zookeep…

《程序员面试金典(第6版)面试题 16.09. 运算

题目描述 请实现整数数字的乘法、减法和除法运算&#xff0c;运算结果均为整数数字&#xff0c;程序中只允许使用加法运算符和逻辑运算符&#xff0c;允许程序中出现正负常数&#xff0c;不允许使用位运算。 你的实现应该支持如下操作&#xff1a; Operations() 构造函数minus…

Linux【模拟实现C语言文件流】

✨个人主页&#xff1a; 北 海 &#x1f389;所属专栏&#xff1a; Linux学习之旅 &#x1f383;操作环境&#xff1a; CentOS 7.6 阿里云远程服务器 文章目录 &#x1f307;前言&#x1f3d9;️正文1、FILE 结构设计2、函数使用及分析3、文件打开 fopen4、文件关闭 fclose5、缓…

4.3 实施部署Nginx 高可用负载均衡集群

部署大致可分为&#xff1a;准备工作、配置、验证与交付几个步骤&#xff0c;接下来按顺序逐一介绍。 4.3.1 准备工作 Nginx高可以负载均衡集群准备工作分两个层面&#xff1a;前端负载均衡器的准备工作与后端真实服务器的准备工作。根据长期实践出来的经验&#xff0c;先准备后…

更轻更好用的蓝牙耳机,日常佩戴更舒适,QCY Crossky Link体验

平时为了方便接打电话&#xff0c;我经常会戴上一副蓝牙耳机&#xff0c;不过戴久了入耳式的耳机&#xff0c;总感觉不舒服&#xff0c;上个月我看到一款设计很新颖的开放式耳机&#xff0c;来自我之前用过的一个国产品牌&#xff0c;最近到手后试了试&#xff0c;感觉质量不错…

Pandoc 从入门到精通,你也可以学会这一个文本转换利器

Pandoc 简介 如果你需要在不同的文件格式之间相互转换&#xff0c;多半听说或使用过文档转换的瑞士军刀——Pandoc。事实上&#xff0c;不仅人类知道 Pandoc&#xff0c;最近很火的人工智能 ChatGPT 也知道「将 Markdown 转换为 docx」&#xff0c;首选方案是使用 Pandoc。 ​…

Codeforces Round 868 (Div. 2)

Problem - D - Codeforces 思路&#xff1a; 首先&#xff0c;一个位置至多贡献1&#xff0c;不然就是0.如[l1,r]与[l2,r]都是回文串&#xff08;l1<l2) 若(l1r)/2<l2,即[l2,r]本身就是[l1,r]回文串右边的一部分&#xff0c;那么他的贡献在[l1,r]左边已经计算过。如果(…

Python程序的执行过程

哈喽&#xff0c;大家好&#xff0c;五一快乐呀&#xff0c;都去哪里旅游了呢&#xff1f;再游玩之余也花点时间来学习学习&#xff0c;让自己更强哟。这期就给大家分享的是Python程序执行的过程学习。 之前已经给大家介绍了Python语言的简介、Python环境的安装、IDE的选择与安…

4 斐波那契数列

4 斐波那契数列 作者: Turbo时间限制: 1S章节: 递归 问题描述 : 斐波那契数列的排列是&#xff1a;0&#xff0c;1&#xff0c;1&#xff0c;2&#xff0c;3&#xff0c;5&#xff0c;8&#xff0c;13&#xff0c;21&#xff0c;34&#xff0c;55&#xff0c;89&#xff0c;…

CTF-PHP反序列化漏洞2-利用魔法函数

作者&#xff1a;Eason_LYC 悲观者预言失败&#xff0c;十言九中。 乐观者创造奇迹&#xff0c;一次即可。 一个人的价值&#xff0c;在于他所拥有的。可以不学无术&#xff0c;但不能一无所有&#xff01; 技术领域&#xff1a;WEB安全、网络攻防 关注WEB安全、网络攻防。我的…

.net 智慧手术麻醉管理系统 WCF框架

实用性&#xff1a; 充分考虑科室业务场景实用性&#xff0c;把满足临床需要为第一要素进行考虑。具有操作简单、提示清晰、逻辑性强&#xff0c;直观简洁等特点。 灵活可自定义&#xff1a; 软件设计采用模块式、组件式开发&#xff0c;根据临床需要可根据实际业务进行组合…

【MATLAB第26期】区间预测 | 基于MATLAB的LASSO分位数回归预测模型 负荷预测数据

【MATLAB第26期】区间预测 | 基于MATLAB的LASSO分位数回归预测模型 负荷预测数据 一、效果预览 MSE: 22.9684327801807 %15分钟 21.6725387054707%30分钟 24.0995456594418%45分钟 21.3992361173462%60分钟 二、数据选择 案例数据&#xff1a;两个月负荷数据3599*30&#x…