synchronized同步块和volatile同步变量

搭建PX4开发系统(Ubuntu 22.04) 本文是《从零开始学 PX4 无人机开发》系列第二篇,适合开发者在 Ubuntu 系统下快速搭建 PX4 编译与仿真环境,支持 QGroundControl、Gazebo、MAVSDK 等完整工具链。 阅读详情

Java语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量。这两种机制的提出都是为了实现代码线程的安全性。其中 Volatile 变量的同步性较差(但有时它更简单并且开销更低),而且其使用也更容易出错。

synchronized同步块

Java中的同步块用synchronized标记。同步块在Java中是同步在某个对象上。所有同步在一个对象上的同步块在同时只能被一个线程进入并执行操作。所有其他等待进入该同步块的线程将被阻塞,直到执行该同步块中的线程退出。

有四种不同的同步块:

  实例方法:一个实例一个线程。

  静态方法:一个类只能由一个线程同时执行。

  实例方法中的同步块

  静态方法中的同步块

在多线程下最好是使用这种:

public class MyClass {

 public static void log2(String msg1, String msg2){
       synchronized(MyClass.class){
          log.writeln(msg1);
          log.writeln(msg2);
       }
    }
}

上述同步块都同步在不同对象上。实际需要那种同步块视具体情况而定。

实例方法同步

下面是一个同步的实例方法:

public synchronized void add(int value){
    this.count += value;
}

注意在方法声明中同步(synchronized )关键字。这告诉Java该方法是同步的。

Java实例方法同步是同步在拥有该方法的对象上。这样,每个实例其方法同步都同步在不同的对象上,即该方法所属的实例。只有一个线程能够在实例方法同步块中运行。如果有多个实例存在,那么一个线程一次可以在一个实例同步块中执行操作。一个实例一个线程。

静态方法同步

静态方法同步和实例方法同步方法一样,也使用synchronized 关键字。Java静态方法同步如下示例:

public static synchronized void add(int value){
 count += value;
}

同样,这里synchronized 关键字告诉Java这个方法是同步的。

静态方法的同步是指同步在该方法所在的类对象上。因为在Java虚拟机中一个类只能对应一个类对象,所以同时只允许一个线程执行同一个类中的静态同步方法。

对于不同类中的静态同步方法,一个线程可以执行每个类中的静态同步方法而无需等待。不管类中的那个静态同步方法被调用,一个类只能由一个线程同时执行。

实例方法中的同步块

有时你不需要同步整个方法,而是同步方法中的一部分。Java可以对方法的一部分进行同步。

在非同步的Java方法中的同步块的例子如下所示:

public void add(int value){
    synchronized(this){
       this.count += value;
    }
  }

示例使用Java同步块构造器来标记一块代码是同步的。该代码在执行时和同步方法一样。

注意Java同步块构造器用括号将对象括起来。在上例中,使用了“this”,即为调用add方法的实例本身。在同步构造器中用括号括起来的对象叫做监视器对象。上述代码使用监视器对象同步,同步实例方法使用调用方法本身的实例作为监视器对象。

一次只有一个线程能够在同步于同一个监视器对象的Java方法内执行。

下面两个例子都同步他们所调用的实例对象上,因此他们在同步的执行效果上是等效的。

public class MyClass {

   public synchronized void log1(String msg1, String msg2){
      log.writeln(msg1);
      log.writeln(msg2);
   }

   public void log2(String msg1, String msg2){
      synchronized(this){
         log.writeln(msg1);
         log.writeln(msg2);
      }
   }
 }

在上例中,每次只有一个线程能够在两个同步块中任意一个方法内执行。

如果第二个同步块不是同步在this实例对象上,那么两个方法可以被线程同时执行。

静态方法中的同步块

和上面类似,下面是两个静态方法同步的例子。这些方法同步在该方法所属的类对象上。

public class MyClass {
    public static synchronized void log1(String msg1, String msg2){
       log.writeln(msg1);
       log.writeln(msg2);
    }

    public static void log2(String msg1, String msg2){
       synchronized(MyClass.class){
          log.writeln(msg1);
          log.writeln(msg2);
       }
    }
  }

这两个方法不允许同时被线程访问。

如果第二个同步块不是同步在MyClass.class这个对象上。那么这两个方法可以同时被线程访问。

Java同步实例

在下面例子中,启动了两个线程,都调用Counter类同一个实例的add方法。因为同步在该方法所属的实例上,所以同时只能有一个线程访问该方法。

public class Counter{
     long count = 0;

     public synchronized void add(long value){
       this.count += value;
     }
  }
  public class CounterThread extends Thread{

     protected Counter counter = null;

     public CounterThread(Counter counter){
        this.counter = counter;
     }

     public void run() {
    for(int i=0; i<10; i++){
           counter.add(i);
        }
     }
  }
  public class Example {

    public static void main(String[] args){
      Counter counter = new Counter();
      Thread  threadA = new CounterThread(counter);
      Thread  threadB = new CounterThread(counter);

      threadA.start();
      threadB.start();
    }
  }

创建了两个线程。他们的构造器引用同一个Counter实例。Counter.add方法是同步在实例上,是因为add方法是实例方法并且被标记上synchronized关键字。因此每次只允许一个线程调用该方法。另外一个线程必须要等到第一个线程退出add()方法时,才能继续执行方法。

如果两个线程引用了两个不同的Counter实例,那么他们可以同时调用add()方法。这些方法调用了不同的对象,因此这些方法也就同步在不同的对象上。这些方法调用将不会被阻塞。如下面这个例子所示:

public class Example {

   public static void main(String[] args){
     Counter counterA = new Counter();
     Counter counterB = new Counter();
     Thread  threadA = new CounterThread(counterA);
     Thread  threadB = new CounterThread(counterB);

     threadA.start();
     threadB.start();
   }
 }

注意这两个线程,threadA和threadB,不再引用同一个counter实例。CounterA和counterB的add方法同步在他们所属的对象上。调用counterA的add方法将不会阻塞调用counterB的add方法。

volatile同步变量

线程为了提高效率,将某成员变量(如A)拷贝了一份(如B),线程中对A的访问其实访问的是B。只在某些动作时才进行A和B的同步。因此存在A和B不一致的情况。volatile就是用来避免这种情况的。volatile告诉jvm, 它所修饰的变量不保留拷贝,直接访问主内存中的(也就是上面说的A) 。

理解volatile特性的一个好方法是:把对volatile变量的单个读/写,看成是使用同一个监视器锁对这些单个读/写操作做了同步。下面我们通过具体的示例来说明

class VolatileFeaturesExample {

    volatile long vl = 0L;  //使用volatile声明64位的long型变量

    public void set(long l) {
        vl = l;   //单个volatile变量的写
    }

    public void getAndIncrement () {
        vl++;    //复合(多个)volatile变量的读/写
    }


    public long get() {
        return vl;   //单个volatile变量的读
    }
}

假设有多个线程分别调用上面程序的三个方法,这个程序在语意上和下面程序等价:

class VolatileFeaturesExample {
    long vl = 0L;               // 64位的long型普通变量

    public synchronized void set(long l) {     //对单个的普通 变量的写用同一个监视器同步
        vl = l;
    }

    public void getAndIncrement () { //普通方法调用
        long temp = get();           //调用已同步的读方法
        temp += 1L;                  //普通写操作
        set(temp);                   //调用已同步的写方法
    }
    public synchronized long get() { 
    //对单个的普通变量的读用同一个监视器同步
        return vl;
    }
}

如上面示例程序所示,对一个volatile变量的单个读/写操作,与对一个普通变量的读/写操作使用同一个监视器锁来同步,它们之间的执行效果相同。

监视器锁的happens-before规则保证释放监视器和获取监视器的两个线程之间的内存可见性,这意味着对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写入。

监视器锁的语义决定了临界区代码的执行具有原子性。这意味着即使是64位的long型和double型变量,只要它是volatile变量,对该变量的读写就将具有原子性。如果是多个volatile操作或类似于volatile++这种复合操作,这些操作整体上不具有原子性。

Unreal5从入门到精通之如何解决在VR项目在头显中卡顿的问题 以前我们使用Unity开发VR,Unity提供了非常便利的插件和工具来做VR。但是由于Unity的渲染效果不如Unreal,现在我们改用Unreal来做VR了,所有的VR相关的配置和操作都要重新学习。今天就来总结一下,我在开发VR过程中碰到的所有问题。好了,以上就是我目前做VR时碰到的一些问题,希望对你有所帮助。 阅读详情

相关推荐

[Unity实战]热更新如何预防过度裁剪

假设你现在有一个游戏客户端,客户端只打包了入口场景,游戏场景都存放在了AB包。

u012587406的博客 1605

同步方法及同步块

由于我们可以通过private关键字来保证数据只能被方法访问,所以我们只需要针对方法提出一套机制,这套机制就是synchronized关键字,它包括两种用法:synchronized方法和synchronized块 1.同步方法 public synchronized void method(int args) {} synchronized方法控制对“对象”的访问,每个对象对应一把锁,每个synchronized方法都必须获得调用该方法的对象的锁才能执行,否则线程会阻塞,方法一旦执行,就独占该锁,直到方

weixin_46751741的博客 1431

【EtherCAT实践篇一】TwinCAT 3安装、使用

FULL(XAE)安装包:包含了XAR的功能,并能进行多种语言的编程和硬件组态,通常安装在编程电脑上;XAR安装包:包含了ADS的功能,是实时运行环境,对 TwinCAT 模块进行加载、执行、管理、实时运行与调用,通常安装在PLC中;RM安装包:在装了高版本的TwinCAT 3后,发现PLC中的TwinCAT版本较低,就需要安装相应低版本的RM安装包切换版本使用(注:4024无法使用RM安装包切换到低于4022的版本,如4020/4018/4016版本。

JXES智能生态系统 5127

多线程(12)同步方法和同步块

在并发编程中,同步方法和同步块是两种常用的同步机制,它们用以确保多线程环境下对共享资源的访问是安全的,防止数据的不一致性和竞态条件的产生。本文将详细探讨这两种同步机制的工作原理、使用场景、优缺点,以及实践中应注意的问题。

qq_43012298的博客 981

脑机接口(BCI)从原理到开发实战 07|运动想象BCI实战:基于BCI Competition IV 2a数据集

本文基于BCI Competition IV 2a数据集,详细介绍运动想象脑机接口系统的全流程实现。首先概述了该数据集的实验范式、参数特点和优势,然后指导环境准备与数据下载。通过代码示例展示了数据加载、事件标记提取和信号可视化方法。重点构建了完整的预处理流水线,包括通道选择、重参考、带通滤波(8-30Hz)和ICA去伪迹等关键步骤。文章旨在帮助读者将零散的BCI知识整合为完整的实战项目,掌握从原始脑电数据到运动意图解码的核心技术。

小明的博客 850

antv x6 沿边图标循环动画实现

2.使用transition给边设置动画,利用complte方法实现循环动画。实现效果,如下图,边上存在两个图标,要求图标延边一直循环动画。1.注册一个自定义边,边上定义两个图标,并设置其初始位置。

lingliu0824的博客 3366

java同步块_java并发(八)Java同步块synchronized

锁提供了两种主要特性互斥(mutual exclusion) 和可见性(visibility)。互斥即一次只允许一个线程持有某个特定的锁,因此可使用该特性实现对共享数据的协调访问协议,这样,一次就只有一个线程能够使用该共享数据。可见性要更加复杂一些,它必须确保释放锁之前对共享数据做出的更改对于随后获得该锁的另一个线程是可见的 —— 如果没有同步机制提供的这种可见性保证,线程看到的共享变量可能是修改...

weixin_29959015的博客 285

手把手教你学Simulink--基础储能管理场景实例:基于Simulink的扩展卡尔曼滤波(EKF)SOC估计算法仿真

本文介绍了基于Simulink的扩展卡尔曼滤波(EKF)在电池SOC估算中的应用。通过Thevenin等效电路建立非线性电池模型,详细阐述了EKF的状态预测和更新过程。在Simulink中搭建了完整的仿真系统,包括电池模型、EKF核心算法模块和误差分析模块。通过脉冲放电和变电流充放电两种工况测试,验证了EKF算法在短期误差(<0.8%)、长期累积误差(<1.5%)和动态响应时间(30ms)方面的优越性能,相比传统安时积分法显著提高了估算精度。文章还提出了自适应EKF、多模型融合等进阶优化方向,为

MHD0815的博客 99

Synchronized实现同步代码块的细节

"synchronized"同步代码块实现的细节

weixin_47474875的博客 601

基于深度学习的堰塞坝表层颗粒物质识别研究

本文提出一种基于深度学习的堰塞坝表层颗粒物质智能识别方法,针对颗粒分布散乱、背景复杂的问题,采用"大颗粒逐个识别、密集小颗粒分块识别"策略。结合Mask R-CNN、SLIC和AlexNet构建识别模型,通过无人机影像实现自动识别。实验表明该方法精度超过90%,具备迁移能力。文章提供了Python实现代码,涵盖数据预处理、SLIC分割、模型构建(Mask R-CNN和AlexNet)及训练流程,为堰塞坝应急抢险提供技术支持。

huanghm88的专栏 181

innovus:给channel加soft blockage

dbGet [dbGet top.fplan.pBlkgs.name finishfp_place_blkg_* -p].boxes就可以获得channel坐标。意思是给30um以下的channel加soft blk,至于channel的坐标,通过抓取该soft blk去获取,比较容易。工具自己加入的placement blockage命名上叫finishfp_place_blkg_*ICC2中有给channel自动加soft blockage的命令,相应的innovus也有类似的命令,我们可以使用。

m0_61544122的博客 483

【synchronized】同步方法与同步块

这里我们分三块来解读学习: 同步方法思想 同步块思想 同步方法与同步块的区别 1. 同步方法思想 上面是我画的同步方法思想简化图,我们将每个对象类比喻为房子,对象类拥有的多个方法比喻为很多房间,有同步锁的方法比喻为有锁的房间(锁放在房间门口),没有同步锁的方法比喻为没有锁的房间,方法的调用者我们将其比喻为想要进入某个房间的人。想进入这些房间有一些规则必须遵守,这里可以比喻为家规吧。 规则: 没有锁的房间可以不用等待进入,而且可以容纳多人; 有锁的房间必须有钥匙才可进入,而且只可容纳一人; 对于有锁的

itbird的专栏 3845

组态王的日历时间控件脚本

日期时间控件中的脚本中在小于10的月份和天数前必须要加上0,这是由首字符对比机制规定的,首字母相同,就不再不做对比了,比如1和11,是一样的。首字母不同,再比较下一位。 float Ayear1; float Amonth1; float Aday1; string temp1; Ayear1=sd.Year; Amonth1=sd.Month; Aday1=sd.Day; temp1=StrFromInt( Ayear1, 10 ); if(Amonth1<10) temp1=temp1+"-0"+

逍遥子的博客 5718

java基础篇(17) synchronized同步块和volatile同步变量

初遇 Java语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量。这两种机制的提出都是为了实现代码线程的安全性。其中 Volatile 变量的同步性较差(但有时它更简单并且开销更低),而且其使用也更容易出错。 synchronized同步块 Java中的同步块用synchronized标记。同步块在Java中是同步在某个对象上。所有同步在一个对象上的同步块在同时只能被一个线程进...

cowbin2012的专栏 1万+

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

java 同步 变量_synchronized同步块和volatile同步变量

Java语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量。这两种机制的提出都是为了实现代码线程的安全性。其中 Volatile 变量的同步性较差(但有时它更简单并且开销更低),而且其使用也更容易出错。synchronized同步块Java中的同步块用synchronized标记。同步块在Java中是同步在某个对象上。所有同步在一个对象上的同步块在同时只能被一个线程进入并执行操...

weixin_34055346的博客 707

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

java基础提升篇:synchronized同步块和volatile同步变量

初遇 Java语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量。这两种机制的提出都是为了实现代码线程的安全性。其中 Volatile 变量的同步性较差(但有时它更简单并且开销更低),而且其使用也更容易出错。 synchronized同步块 Java中的同步块用synchronized标记。同步块在Java中是同步在某个对象上。所有同步在一个对象上的同步块在同时只能被...

好好学java 492

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Java synchronized同步块和同步函数的区别

详细介绍了Java线程同步的概念以及常用方法,重点介绍了同步块和同步函数。

终生学习践行者 2187

Java多线程-synchronized和volatile区别

锁提供了两种主要特性: 互斥性:一次只允许一个线程持有某个锁 可见性:确保新值立即同步到主存,每次使用前立即从主存刷新 synchronized和volatile: 为了保证多线程读写数据时数据的一致性 synchronized同步:释放锁之前将会对变量的修改刷新到主存中;阻塞;synchronized可以保证变量修改的可见性和原子性 volatile:确保新值立即同步到主存,每次使用前立即从主存刷新,可以理解为直接操作主存,实现变量修改的可见性,有序性;非阻塞; volatile:对任意单

weixin_42376667的博客 427

Java并发编程的艺术笔记(一)——volatile和syncronized关键字

一.线程间的通信 volatile和syncronized关键字 volatile 修饰变量,告知任何对该变量的访问必须从共享内存获取,对它的改变必须同步刷新至共享内存,由此保证可见性。 syncronized修饰方法和同步块 syncronized的实现细节 写一个java类: public class Synchronized { public static void mai...

weixin_30871293的博客 99

java并发中的volatile和synchronized

撸了今年阿里、网易和美团的面试,我有一个重要发现.......>>> ...

王念的博客 140

正确使用 Volatile 变量

Java™ 语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量。这两种机制的提出都是为了实现代码线程的安全性。其中 Volatile 变量的同步性较差(但有时它更简单并且开销更低),而且其使用也更容易出错。 Java 语言中的 volatile 变量可以被看作是一种 “程度较轻的 synchronized”;与 synchronized 块相比,volatile 变量所...

Be a man 291
上一篇: Java中的装箱和拆箱
下一篇: Java中的集合框架
ohmygodvv
博客等级 码龄4年 521粉丝 140原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ohmygodvv

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值