`

Volatile与sychronized

    博客分类:
  • Java
 
阅读更多

    在使用 volatile 关键字时要慎 重,并不是只要简单类型变量使用 volatile 修饰,对这个变量的所有操作都是原来操作,当变量的值由自身的上一个决定时,如 n=n+1 n++ 等, volatile 关键字将失效,只有当变量的值和自身上一个值无关时对该变量的操作才是原子级别的,如 n = m + 1 ,这个就是原级别的。所以在使用 volatile 关键时一定要谨慎,如果自己没有把握,可以使用 synchronized 来代替 volatile

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

Synchronized: 同步方法或变量的同时也锁定了类

 

 

深入了解 synchronized 及对象锁

2008-09-09 10:361 , Synchronized 锁定的是对象而非函数或代码。

2 , 每个 Object 只有一把锁 (Lock) 与之关联,当进行到 Synchronized 语句或函数的时候,这把锁就会被当前的线程( thread )拿走,其他的( thread )再去访问的时候拿不到锁就被暂停了

3, 只有当 Synchronized 的是同一个对象的才是线程安全的( thread-safe

:

    1) public Synchronized void method1 : 锁住的是该对象 , 类的其中一个实例 , 当该对象 ( 仅仅是这一个对象 ) 在不同线程中执行这个同步方法时 , 线程之间会形成互斥 . 达到同步效果 , 但如果不同线程同时对该类的不同对象执行这个同步方法时 , 则线程之间不会形成互斥 , 因为他们拥有的是不同的锁 .

    2) Synchronized(this){ //TODO } 同一

 

    3) public Synchronizedstatic void method3 : 锁住的是该类 , 当所有该类的对象 ( 多个对象 ) 在不同线程中调用这个 static 同步方法时 , 线程之间会形成互斥 , 达到同步效果 , 但如果多个线程同时调用 method1 , method3, 则不会引互斥 , 具体讲看最后讲解 .

    4) Synchronized(Test.class){ //TODo} 同三

 

    5) synchronized(o) {} 这里面的 o 可以是一个任何 Object 对象或数组 , 并不一定是它本身对象或者类 , 谁拥有 o 这个锁 , 谁就能够操作该块程序代码 .

 

这里面 1) 2) 是线程安全的 , 1) 3) , 2) 3) 他们所拥有的锁不一样 , 故不是同步的 , 不是线程安全的 .

 

 

最后 , synchronized 所同步的代码应该尽量少 . 如果没有必要同步的就不要列为其中

     联想到数据库的并发控制

假如有如下操作

    1) 从数据库中读取数据

    2) 修改数据

    3) 提交数据

解决方案一

1) 读取数据

synchronized(XXX)

{

    2) 修改数据

    3) 提交数据

解决方案二

synchronized(XXX)

{

    1) 读取数据

    2) 修改数据

    3) 提交数据

}

 

解决方案三

synchronized(XXX)

{

     3) 提交数据

}

 

这里面到底用哪一种方案视具体情况而定 , 要注意的是 synchronized( 同步 ) 的代价 , 开销是很大的 .

 

 

 

volatile 关键字有什么用?

  恐怕比较一下 volatile synchronized 的不同是最容易解释清楚的。 volatile 是变量修饰符,而 synchronized 则作用于一段代码或方法;看如下三句 get 代码:

int i1;                          int geti1() {return i1;}

volatile int i2;              int geti2() {return i2;}

int i3; synchronized     int geti3() {return i3;}

 

   geti1() 得到存储在当前线程中 i1 的数值。多个线程有多个 i1 变量拷贝,而且这些 i1 之间可以互不相同。换句话说,另一个线程可能已经改变了它线程内的 i1 值,而这个值可以和当前线程中的 i1 值不相同。事实上, Java 有个思想叫“主”内存区域,这里存放了变量目前的“准确值”。每个线程可以有它自己的变量拷贝,而这个变量拷贝值可以和“主”内存区域里存放的不同。因此实际上存在一种可能:“主”内存区域里的 i1 值是 1 ,线程 1 里的 i1 值是 2 ,线程 2 里的 i1 值是 3 ——这在线程 1 和线程 2 都改变了它们各自的 i1 值,而且这个改变还没来得及传递给“主”内存区域或其他线程时就会发生。

  而 geti2() 得到的是“主”内存区域的 i2 数值。用 volatile 修饰后的变量不允许有不同于“主”内存区域的变量拷贝。换句话说,一个变量经 volatile 修饰后在所有线程中必须是同步的;任何线程中改变了它的值,所有其他线程立即获取到了相同的值。理所当然的, volatile 修饰的变量存取时比一般变量消耗的资源要多一点,因为线程有它自己的变量拷贝更为高效。

  既然 volatile 关键字已经实现了线程间数据同步,又要 synchronized 干什么呢?呵呵,它们之间有两点不同。首先, synchronized 获得并释放监视器——如果两个线程使用了同一个对象锁,监视器能强制保证代码块同时只被一个线程所执行——这是众所周知的事实。但是, synchronized 也同步内存:事实上, synchronized 在“主”内存区域同步整个线程的内存。因此,执行 geti3() 方法做了如下几步:

1. 线程请求获得监视 this 对象的对象锁(假设未被锁,否则线程等待直到锁释放)

2. 线程内存的数据被消除,从“主”内存区域中读入( Java 虚拟机能优化此步。。。 [ 后面的不知道怎么表达 , ]

3. 代码块被执行

4. 对于变量的任何改变现在可以安全地写到“主”内存区域中(不过 geti3() 方法不会改变变量值)

5. 线程释放监视 this 对象的对象锁

  因此 volatile 只是在线程内存和“主”内存间同步某个变量的值,而 synchronized 通过锁定和解锁某个监视器同步所有变量的值。显然 synchronized 要比 volatile 消耗更多资源。

分享到:
评论

相关推荐

    C#中volatile与lock用法

    本文实例讲述了C#中volatile与lock用法,分享给大家供大家参考。具体分析如下: 一、C#中volatile volatile是C#中用于控制同步的关键字,其意义是针对程序中一些敏感数据,不允许多线程同时访问,保证数据在任何访问...

    Volatile详解,深入学习Volatile

    Volatile是C/C++编程语言中的一个关键字,它与const一起被称为"cv特性",用于指示变量的值可能被系统或其他线程/进程改变,从而强制编译器每次从内存中读取该变量的最新值。在多线程或嵌入式编程中,volatile的作用...

    volatile与synchronized的区别

    volatile与synchronized的区别,锁提供了两种主要特性:互斥(mutual exclusion) 和可见性(visibility)

    Java volatile与AQS锁内存可见性

    从JUC中的AQS引入,讲解Java volatile与AQS锁内存可见性

    volatile变量详解

    volatile 变量详解 volatile 变量是一种特殊类型的变量,关键字 volatile 作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。简单地说就是防止编译器对代码进行优化。 volatile 变量的...

    stm32 volatile变量的正确使用

    - **`volatile`与多线程/多任务:** - 即使使用了`volatile`,也不能保证数据的原子性。在多线程或多任务环境中,还需要结合互斥锁等机制来保证数据访问的一致性和安全性。 #### 结论 在嵌入式系统编程中,正确...

    volatile的用法讲解

    2. volatile修饰符不能与const修饰符同时使用,因为volatile修饰符意味着变量的值可能会改变,而const修饰符意味着变量的值不能改变。 3. 使用volatile修饰符可能会影响编译器的优化,因此需要根据实际情况进行选择...

    volatile用法

    `volatile`关键字在C语言中是一个非常重要的概念,主要用于处理多线程环境或者与硬件交互时的内存可见性问题。它的主要作用是确保对变量的修改能够立即反映到所有线程,防止编译器进行不必要的优化,使得其他线程...

    Java线程:volatile关键字

    与 synchronized 块相比,volatile 变量所需的编码较少,并且运行时开销也较少,但是它所能实现的功能也仅是 synchronized 的一部分。 volatile 变量具有 synchronized 的可见性特性,但是不具备原子特性。这就是说...

    volatile的使用方法

    在第二个例子中,我们可以看到,如果不使用 volatile 关键字,编译器可能会对变量 p 进行优化,从而导致编译后的汇编代码与我们的预期不符。只有当我们使用 volatile 关键字时,编译器才会按照我们编写的代码来生成...

    volatile的用法

    9. volatile与编译器生成的汇编代码:使用volatile的变量会阻止编译器执行某些优化措施,这可能导致生成的汇编代码中包含了额外的指令。例如,在一个循环中,如果变量没有被声明为volatile,编译器可能会优化掉对这...

    volatile源码分析1

    【volatile源码分析1】 Java中的volatile关键字是一个关键的同步机制,它在多线程编程中扮演着重要的角色。在面试和技术讨论中,volatile经常成为焦点,但其工作原理却常常引发争议。本文将从JVM、C++以及汇编语言...

    const和volatile分析

    5. `volatile`与`const`结合:`volatile const`变量表示其值可以被外部因素改变,但程序内部不应尝试修改。 在面试和找工作中,理解和掌握`const`和`volatile`的使用是评估程序员基础功底的重要标准。熟悉它们可以...

    单片机C语言中volatile的作用

    这是因为单片机经常需要与外部硬件设备进行交互,而这些设备的操作往往具有不确定性,比如硬件寄存器的值可能会因为外部事件而发生变化。在这种情况下,如果不正确地管理变量,可能会导致程序运行出现错误。 #### `...

    volatile详解

    #### 一、volatile的基本概念与作用 `volatile`关键字在编程语言中扮演着重要的角色,尤其是在处理并发编程、嵌入式系统开发等领域。`volatile`的中文含义通常被翻译为“易变的”,但根据描述中的观点,将其理解为...

    单片机中volatile定义的作用

    这对于单片机编程非常重要,因为单片机程序经常需要与硬件、中断、RTOS等打交道。 在单片机编程中,volatile关键字经常用于以下几种情况: 1. 中断服务程序中修改的供其它程序检测的变量需要加volatile 2. 多任务...

    volatile 变量的说明

    volatile变量在编程语言中,尤其是Java和C/C++中,是一种特殊的标识符,用于指示编译器该变量的值可能在编译器不知情的情况下发生变化。这个关键字的主要作用是告诉编译器不要对这个变量进行优化,每次使用时都需要...

    C中volatile_const解析

    ### C中`volatile`与`const`解析 #### 概述 在C语言中,`volatile`和`const`是两个非常重要的关键字,它们在不同的场景下有着独特的用途。掌握这两个关键字不仅能够帮助开发者写出更加高效和可靠的代码,还能够在...

    java volatile 关键字实战

    java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java volatile 关键字实战java ...

Global site tag (gtag.js) - Google Analytics