`
夜枫舞影
  • 浏览: 50591 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Java Volatile transient

阅读更多
Java Volatile transient

Java Volatile说明     

http://blog.csdn.net/blueheart20/archive/2007/04/29/1591874.aspx

在Java中设置变量值的操作,除了long和double类型的变量外都是原子操作,也就是说,对于变量值的简单读写操作没有必要进行同步。这在 JVM 1.2之前,Java的内存模型实现总是从主存读取变量,是不需要进行特别的注意的。而随着JVM的成熟和优化,现在在多线程环境下volatile关键字的使用变得非常重要。在当前的Java内存模型下,线程可以把变量保存在本地内存(比如机器的寄存器)中,而不是直接在主存中进行读写。这就可能造成一个线程在主存中修改了一个变量的值,而另外一个线程还继续使用它在寄存器中的变量值的拷贝,造成数据的不一致。要解决这个问题,只需要像在本程序中的这样,把该变量声明为volatile(不稳定的)即可,这就指示JVM,这个变量是不稳定的,每次使用它都到主存中进行读取。一般说来,多任务环境下各任务间共享的标志都应该加volatile修饰。

在实际工作中很少有用到volatile这个关键字,今天在看一段开源代码时碰到它,查了一下它的用法 :

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




Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1591874

http://blog.csdn.net/caoi/archive/2006/03/28/640939.aspx

谈谈Java关键字transient和volatile。

        transient
        把一个对象的表示转化为字节流的过程称为串行化serialization,从字节流中把对象重建出来称为反串行化deserialization,transient 为不应被串行化的数据提供了一个语言级的标记数据方法。
        对象的序列化(serialization)非常影响I/O的性能,尽量少用。对不需序列化的类的域使用transient关键字,以减少序列化的数据量。

         参考:Serializable(中文,英文)
                     Java Serialization Example
                     Serializable java序列化可能带来的问题
                     空接口的使用(给JAVA设计开发新手的一些建议和意见)

        volatile
       在Java中设置变量值的操作,除了long和double类型的变量外都是原子操作,也就是说,对于变量值的简单读写操作没有必要进行同步。这在JVM 1.2之前,Java的内存模型实现总是从主存读取变量,是不需要进行特别的注意的。而随着JVM的成熟和优化,现在在多线程环境下volatile关键字的使用变得非常重要。在当前的Java内存模型下,线程可以把变量保存在本地内存(比如机器的寄存器)中,而不是直接在主存中进行读写。这就可能造成一个线程在主存中修改了一个变量的值,而另外一个线程还继续使用它在寄存器中的变量值的拷贝,造成数据的不一致。要解决这个问题,只需要像在本程序中的这样,把该变量声明为volatile(不稳定的)即可,这就指示JVM,这个变量是不稳定的,每次使用它都到主存中进行读取。一般说来,多任务环境下各任务间共享的标志都应该加volatile修饰。(来源和其他参考 )

http://blog.csdn.net/ai92/archive/2005/03/08/315183.aspx

初探关键字volatile     

第一次接触到关键字volatile,不知为何物,只是模糊的记得java关键字里面好像有它。查了些资料,整理如下:

Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。

Java语言规范中指出:为了获得最佳速度,允许线程保存共享成员变量的私有拷贝,而且只当线程进入或者离开同步代码块时才与共享成员变量的原始值对比。

这样当多个线程同时与某个对象交互时,就必须要注意到要让线程及时的得到共享成员变量的变化。

而volatile关键字就是提示VM:对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。

使用建议:在两个或者更多的线程访问的成员变量上使用volatile。当要访问的变量已在synchronized代码块中,或者为常量时,不必使用。

由于使用volatile屏蔽掉了VM中必要的代码优化,所以在效率上比较低,因此一定在必要时才使用此关键字。

http://blog.csdn.net/majorboy/archive/2005/09/09/475811.aspx

关于volatile和synchronized     

这个可能是最好的对比volatile和synchronized作用的文章了。volatile是一个变量修饰符,而synchronized是一个方法或块的修饰符。所以我们使用这两种关键字来指定三种简单的存取变量的方式。

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

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

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

geti1()在当前线程中立即获取在i1变量中的值。线程可以获得变量的本地拷贝,而所获得的变量的值并不一定与其他线程所获得的值相同。特别是,如果其他的线程修改了i1的值,那么当前线程获得的i1的值可能与修改后的值有所差别。实际上,Java有一种主内存的机制,使用一个主内存来保存变量当前的正确的值。线程将变量的值拷贝到自己独立的内存中,而这些线程的内存拷贝可能与主内存中的值不同。所以实际当中可能发生这样的情况,在主内存中i1的值为1,线程1和线程2都更改了i1,但是却没把更新的值传回给主内存或其他线程中,那么可能在线程1中i1的值为2,线程2中i1的值却为3。

另一方面,geti2()可以有效的从主内存中获取i2的值。一个volatile类型的变量不允许线程从主内存中将变量的值拷贝到自己的存储空间。因此,一个声明为volatile类型的变量将在所有的线程中同步的获得数据,不论你在任何线程中更改了变量,其他的线程将立即得到同样的结果。由于线程存取或更改自己的数据拷贝有更高的效率,所以volatile类型变量在性能上有所消耗。

那么如果volatile变量已经可以使数据在线程间同步,那么synchronizes用来干什么呢?两者有两方面的不同。首先,synchronized获取和释放由监听器控制的锁,如果两个线程都使用一个监听器(即相同对象锁),那么监听器可以强制在一个时刻只有一个线程能处理代码块,这是最一般的同步。另外,synchronized还能使内存同步。在实际当中,synchronized使得所有的线程内存与主内存相同步。所以geti3()的执行过程如下:

1.    线程从监听器获取对象的锁。(这里假设监听器非锁,否则线程只有等到监听器解锁才能获取对象锁)

2.    线程内存更新所有的变量,也就是说他将读取主内存中的变量使自己的变量保证有效。(JVM会使用一个“脏”标志来最优化过程,使得仅仅具有“脏”标志变量被更新。详细的情况查询JAVA规范的17.9)

3.    代码块被执行(在这个例子中,设置返回值为刚刚从主内存重置的i3当前的值。)

4.    任何变量的变更将被写回到主内存中。但是这个例子中geti3()没有什么变化。

5.    线程释放对象的锁给监听器。

所以volatile只能在线程内存和主内存之间同步一个变量的值,而synchronized则同步在线程内存和主内存之间的所有变量的值,并且通过锁住和释放监听器来实现。显然,synchronized在性能上将比volatile更加有所消耗。

破除java神话之三:原子操作都是线程安全的     

java中原子操作是线程安全的论调经常被提到。根据定义,原子操作是不会被打断地的操作,因此被认为是线程安全的。实际上有一些原子操作不一定是线程安全的。

这个问题出现的原因是尽量减少在代码中同步关键字。同步会损害性能,虽然这个损失因JVM不同而不同。另外,在现代的JVM中,同步的性能正在逐步提高。尽管如此,使用同步仍然是有性能代价的,并且程序员永远会尽力提高他们的代码的效率,因此这个问题就延续了下来。

在java 中,32位或者更少位数的赋值是原子的。在一个32位的硬件平台上,除了double和long型的其它原始类型通常都是使用32位进行表示,而 double和long通常使用64位表示。另外,对象引用使用本机指针实现,通常也是32位的。对这些32位的类型的操作是原子的。

这些原始类型通常使用32位或者64位表示,这又引入了另一个小小的神话:原始类型的大小是由语言保证的。这是不对的。java语言保证的是原始类型的表数范围而非JVM中的存储大小。因此,int型总是有相同的表数范围。在一个JVM上可能使用32位实现,而在另一个JVM上可能是64位的。在此再次强调:在所有平台上被保证的是表数范围,32位以及更小的值的操作是原子的。

那么,原子操作在什么情况下不是线程安全的?主要的一点是他们也许确实是线程安全的,但是这没有被保证!java线程允许线程在自己的内存区保存变量的副本。允许线程使用本地的私有拷贝进行工作而非每次都使用主存的值是为了提高性能。考虑下面的类:


class RealTimeClock
{
private int clkID;
public int clockID()
{
  return clkID;
}
public void setClockID(int id)
{
  clkID = id;
}
//...
}

现在考虑RealTimeClock的一个实例以及两个线程同时调用setClockID和clockID,并发生以下的事件序列:

T1 调用setClockID(5)
T1将5放入自己的私有工作内存
T2调用setClockID(10)
T2将10放入自己的私有工作内存
T1调用clockID,它返回5
5是从T1的私有工作内存返回的

对clockI的调用应该返回10,因为这是被T2设置的,然而返回的是5,因为读写操作是对私有工作内存的而非主存。赋值操作当然是原子的,但是因为JVM允许这种行为,因此线程安全不是一定的,同时,JVM的这种行为也不是被保证的。

两个线程拥有自己的私有拷贝而不和主存一致。如果这种行为出现,那么私有本机变量和主存一致必须在以下两个条件下:

1、变量使用volatile声明
2、被访问的变量处于同步方法或者同步块中

如果变量被声明为volatile,在每次访问时都会和主存一致。这个一致性是由java语言保证的,并且是原子的,即使是64位的值。(注意很多JVM没有正确的实现volatile关键字。你可以在www.javasoft.com找到更多的信息。)另外,如果变量在同步方法或者同步块中被访问,当在方法或者块的入口处获得锁以及方法或者块退出时释放锁是变量被同步。
使用任何一种方法都可以保证ClockID返回10,也就是正确的值。变量访问的频度不同则你的选择的性能不同。如果你更新很多变量,那么使用volatile可能比使用同步更慢。记住,如果变量被声明为volatile,那么在每次访问时都会和主存一致。与此对照,使用同步时,变量只在获得锁和释放锁的时候和主存一致。但是同步使得代码有较少的并发性。

如果你更新很多变量并且不想有每次访问都和主存进行同步的损失或者你因为其它的原因想排除并发性时可以考虑使用同步。

转:http://psupsuoooo.blog.163.com/blog/static/3184148200801262539664/


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/xymyeah/archive/2008/10/31/3193187.aspx
分享到:
评论
1 楼 jack547155187 2011-01-07  
不错。学习了

相关推荐

    Java_transient关键字

    ### Java中的transient关键字详解 在Java编程语言中,`transient`关键字是一个非常重要的概念,主要用于对象序列...同时,理解`transient`与`volatile`之间的区别也是处理复杂Java应用中的多线程和序列化问题的关键。

    java学习_java语法基础

    总结起来,Java的语法基础是编程学习的基础,包括关键字的使用、数据类型的理解和并发控制的关键字如volatile的运用。深入理解这些基础知识,对于编写高效、可靠的Java代码至关重要。在进行多线程编程时,合理利用...

    JAVA笔试总结 -- 非常全面

    native,transient,volatile,strictfp,CMM,synchronized,java socket,压缩与解压缩,多线程,垃圾回收算法,JVM ClassLoader,IO流,反射机制,JNDI, GUI布局管理器,JMS, Java Mail, JNDI reference,java事件处理...

    java面试100题

    Java 中的关键字有 native、strictfp、transient 和 volatile 等。 1. native 修饰符,表示方法是由另外一种语言(如 c/c++,FORTRAN,汇编)实现的本地方法。 2. strictfp 修饰符,表示类或方法遵守 IEEE-754 规范...

    java关键字总结文档

    ### Java关键字总结 Java是一种广泛使用的面向对象编程语言,它具备简单性、可移植性、高性能等特点。在Java中,关键字具有特殊的语法含义,不能用作标识符(例如变量名或方法名)。以下是对给定文件中提到的Java...

    《Java技术指南2019》

    以及Java中的关键字,如transient、instanceof、volatile等的原理及用法。此外,还介绍了Java集合类的使用,枚举的用法和Java IO与NIO的使用和原理,Java反射机制,序列化和反序列化的原理和安全问题,以及注解的...

    Java面试要点(适用于2年以上经验,1年亦可)

    9. 熟悉 Java 中各种关键字:transient、instanceof、volatile、synchronized、final、static、const 集合类 1. ArrayList 和 LinkedList 和 Vector 的区别 2. SynchronizedList 和 Vector 的区别 3. HashMap、...

    Java序列化

    5. **transient和volatile关键字** - `transient` 关键字可以标记字段,表示这个字段不应该参与序列化过程,即不会被序列化到字节流中。 - `volatile` 关键字与序列化无关,但通常与多线程同步有关,序列化时不会...

    JAVA语法大全(基本语法)

    JAVA关键字共有50多个,包括abstract、boolean、break、byte、case、catch、char、class、const、continue、default、do、double、else、extends、final、finally、float、for、goto、if、implements、import、...

    Java Interview Questions for 5 years Experience.pdf

    在Java中,Volatile和Transient是两个关键字,用于修饰变量。Volatile变量保证了多线程环境下的可见性和有序性,确保变量的最新值被所有线程所见。Transient变量则标记了对象的某个字段不需要被序列化。 2. Vector...

    计算机Java核心编程笔记

    Java修饰符包括public、protected、private、final、void、static、strict、abstract、transient、synchronized、volatile、native等。 七、Java流程控制 Java流程控制语句包括package、import、throw、throws、...

    java 对象流 的用法

    2. **transient和volatile关键字**:`transient`关键字用于标记不会被序列化的字段,而`volatile`关键字与序列化无关,但会影响到变量的可见性和同步性。 3. **序列化流的安全性**:序列化可能会暴露对象的内部状态...

    java面试题大全

    1. **关键字 transient 和 volatile**: - `transient` 是Java的关键字,用于标记字段,表明该字段的值不会在序列化过程中被持久化。这意味着当对象被序列化后,被`transient`修饰的变量将不会包含在序列化的表示中...

    Java入门——Java修饰词总结

    Java作为一门广泛使用的编程语言,拥有丰富的语法结构和关键字,其中修饰词(modifiers)是Java语言中的重要组成部分,用于限定类、方法、字段等的访问级别、生命周期以及特性。以下是对Java中11个修饰词的详细介绍...

    2021年JAVA面向对象程序设计练习题库B.doc

    Java 中的 volatile 关键字是指当前对象的状态是易变的。在 Java 中,我们可以使用 volatile 关键字来定义对象的易变状态。 Java 中的 transient 关键字是指当前对象的状态是暂时的。在 Java 中,我们可以使用 ...

    2021年Java大厂面试题整理大全

    1. 线程:掌握线程的创建、同步和协作,包括synchronized、volatile、ThreadLocal关键字的用法。 2. Executor框架:理解ExecutorService、ThreadPoolExecutor和Future接口的应用。 3. Lock接口:了解ReentrantLock、...

    Java语法大全史上最全语法

    - `volatile`: 用于多线程环境中变量的可见性。 - `while`: 用于创建while循环。 ### 示例代码解析 下面是一个简单的Java程序示例: ```java public class HelloWorld { public static void main(String[] args)...

    Java关键字的用法

    ### Java关键字的用法 Java作为一种广泛使用的编程语言,拥有丰富的关键字来支持其核心功能与特性。本文将详细介绍部分重要的Java关键字及其用法。 #### 1. `abstract` `abstract`关键字用于定义抽象类或抽象方法...

Global site tag (gtag.js) - Google Analytics