`
dragonzhu
  • 浏览: 14701 次
  • 性别: Icon_minigender_1
  • 来自: 上海
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

Transient 和volatile

JVM 
阅读更多
(原文来自http://www.devx.com/tips/Tip/13726)
Expertise: Intermediate
Language: Java
January 28, 2000
Be Careful With Transient Data
Java's serialization provides an elegant, and easy to use mechanism for making an object's state persistent. While controlling object serialization, we might have a particular object data member that we do not want the serialization mechanism to save.

To turn off serialization on a certain field of an object, we tag that field of the class of our object with the Java's "transient" keyword. This, to low-level parts of the Java virtual machine, is an indication that the transient variable is not part of the persistent state of an object.

First, let's have some backgrounder code with Java's serialization.
Suppose we define a class as:

 
public class LoggingInfo implements java.io.Serializable
{
private Date loggingDate = new Date();
private String uid;
private transient String pwd;

LoggingInfo(String user, String password)
{
uid = user;
pwd = password;
}
public String toString()
{
String password=null;
if(pwd == null)
{
password = "NOT SET";
}
else
{
password = pwd;
}
return "logon info: \n " + "user: " + uid +
"\n logging date : " + loggingDate.toString() +
"\n password: " + password;
}
}
Now we can create an instance of this class and serialize it, and write the serialized object to disk as in:
 
LoggingInfo logInfo = new LoggingInfo("MIKE", "MECHANICS");
System.out.println(logInfo.toString());
try
{
ObjectOutputStream o = new ObjectOutputStream(
new FileOutputStream("logInfo.out"));
o.writeObject(logInfo);
o.close();
}
catch(Exception e) {//deal with exception}
To read the object back, we can write
 
try
{
ObjectInputStream in =new ObjectInputStream(
new FileInputStream("logInfo.out"));
LoggingInfo logInfo = (LoggingInfo)in.readObject();
System.out.println(logInfo.toString());
}
catch(Exception e) {//deal with exception}
If we run this code, we notice that the read-back object prints password as "NOT SET". This is exactly the effect we should have expected when we declared the pwd field as transient.

Now, let's see a potential problem that careless treatment of transient fields may cause. Suppose we modify our class definition and provide default values for the transient field, say we write:

 
public class GuestLoggingInfo implements java.io.Serializable
{
private Date loggingDate = new Date();
private String uid;
private transient String pwd;

GuestLoggingInfo()
{
uid = "guest";
pwd = "guest";
}
public String toString()
{
//same as above
}
}
Now, if we serialize an instance of GuestLoggingInfo, write it to disk, and read it back, we still see that the read-back object prints password as "NOT SET". In effect, the process of reading back (de-serializing) totally ignores the constructor of GuestLoggingInfo. So what happened?

The answer lies in the fact that the initialization code is not called because we are not initializing, in other words, we are not constructing a brand new object, but loading back the persistent state of an object of a class, and assigning that state to another object of the same class. Declaring the pwd field as transient, excludes the data for that field from the persistent state of our object. Then, upon de-serialization, since there is no data preserved for the pwd field, the field gets Java's default value for its type (null for String).

So, if you mark a field of an object as transient, and write that object to disk, expect to have the default value of the type of that field when you de-serialize the object, and not the actual value that the field had before its state was serialized. If a default value (or any meaningful value) is essential for a transient field of a de-serialized object, you have to assign it yourself either directly (if the field is public) or via a setter method.

Behrouz Fallahi

Java语言的关键字,用来表示一个域不是该对象串行化的一部分。当一个对象被串行化的时候,transient型变量的值不包括在串行化的表示中,然而非transient型的变量是被包括进去的。Serializable接口不实现任何方法,仅仅是做个标识。

  Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
       Java语言规范中指出:为了获得最佳速度,允许线程保存共享成员变量的私有拷贝,而且只当线程进入或者离开同步代码块时才与共享成员变量的原始值对比。
       这样当多个线程同时与某个对象交互时,就必须要注意到要让线程及时的得到共享成员变量的变化。
而volatile关键字就是提示VM:对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。
使用建议:在两个或者更多的线程访问的成员变量上使用volatile。当要访问的变量已在synchronized代码块中,或者为常量时,不必使用。
       由于使用volatile屏蔽掉了VM中必要的代码优化,所以在效率上比较低,因此一定在必要时才使用此关键字。
=================================================================================
       线程为了提高效率,将某成员变量(如A)拷贝了一份(如B),线程中对A的访问其实访问的是B。
      只在某些动作时才进行A和B的同步。因此存在A和B不一致的情况。volatile就是用来避免这种情况的。
      volatile告诉jvm, 它所修饰的变量不保留拷贝,直接访问主内存中的(也就是上面说的A)

 

 

分享到:
评论

相关推荐

    Java开发腾讯面试重点解析-关键字与语法

    内容概要:本文详细解析了 Java 开发中常见的面试题,涵盖了 static 关键字、transient 和 volatile 关键字以及 synchronized 的原理和应用。针对每个关键字,文章不仅介绍了其基本概念,还通过具体代码示例进行了...

    java面试题大全

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

    java面试100题

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

    面向对象主要概念

    成员变量可以有访问修饰符(public、protected、private)、静态、final、transient和volatile等属性,而方法则可以是抽象、final、native、synchronized等。 通过这些概念,开发者可以创建出更符合人类思维习惯、...

    Java就业培训教程(44页).ppt

    关键字this指的是当前对象,static用于声明静态成员,transient和volatile与数据同步和序列化有关,而synchronized确保了多线程环境下的数据安全。 面向对象编程是Java的核心特性,包括类、对象、封装、继承和多态...

    JAVA访问修饰符大归纳

    属性的访问修飾符共有八种:public、private、protected、默认、final、static、transient 和volatile。 * public:任何包、任何类都可以访问。 * private:只能被自身类访问。 * protected:自身类、子类、同一...

    java 对象流 的用法

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

    Java序列化与反序列化<转>

    2. **transient和volatile关键字**:`transient`修饰的字段不会被序列化,而`volatile`关键字与此无关,它用于保证变量的可见性和同步性。 3. **序列化流的安全性**:序列化的数据可以被恶意用户篡改,因此,敏感...

    Java序列化

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

    类的序列化

    3. **transient和volatile关键字**:`transient`关键字用于标记那些不应该序列化的成员变量,它们在序列化过程中会被忽略。`volatile`关键字则与线程同步有关,序列化时不特别处理,但需要注意的是,序列化不保证...

    C语言工程师面试宝典

    1. transient 和 volatile 是 java 关键字吗? 2. 抽象类和接口有什么区别? 3. 能说一下 java 的反射机制吗? 4. 詀 va 中怎样实现多线程? 5. 你用过哪种设计模式? 6. 请说一下 MVC 架构 7. 如果类 a 继承类 b,...

    软件开发技术面试常见题目

    1. transient 和 volatile 是 Java 关键字吗? 2. 抽象类和接口有什么区别? 3. 能说一下 Java 的反射机制吗? 4. 在 Java 中怎样实现多线程? 5. 你用过哪种设计模式? 6. 请说一下 MVC 架构。 7. 如果类 a 继承类 ...

    java英文对照表

    短整型(Short)用于存储较小的整数,特殊修饰符(Special Modifier)可能包括final、transient和volatile。 静态(Static)关键字用于声明类级别的成员,子类(Subclass)继承自超类(Superclass)。开关语句...

    Java_transient关键字

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

    Java 语言基础 —— 非常符合中国人习惯的Java基础教程手册

    观事务的软件化模拟,是变量(数据和数据结构)和相关方法(对数据操作和对象管理的程 序)的软件组合。 在面向对象的程序设计中,你可以用软件对象表示现实世界的对象,而这些软件对象和 现实世界对象是相对应的。...

    java8集合源码-Java:Java

    Java中的transient和volatile变量有什么区别? 提及同步块的用途 基于散列的集合中加载因子的默认大小是多少? 编写代码使集合只读? 区分谓词和函数? Java8中的Nashorn是什么? JVM 分配了多少种内存区域? 定义为...

    serialization-api:跨平台且可通用的Java序列化API

    5. ** transient 和 volatile 关键字**:transient关键字用于标记那些不应该在序列化过程中保存的成员变量。而volatile关键字与序列化无关,但它确保了多线程环境下的可见性和有序性。 6. **自定义序列化和反序列化...

    Java序列化机制与原理的深入分析

    序列化也支持transient和volatile关键字。`transient`修饰的字段不会被序列化,因为它们可能包含瞬态或临时信息。`volatile`字段的序列化行为与非`volatile`字段相同,但在反序列化后,它们不会保留原来的 volatile ...

    详解Java中对象序列化与反序列化

    2. **transient和volatile关键字**:`transient`修饰的字段不会被序列化,`volatile`关键字不影响序列化,但影响字段的可见性和同步性。 3. **循环引用**:序列化时需注意对象间的循环引用,可能会导致无限递归和栈...

    JAVA笔试总结 -- 非常全面

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

Global site tag (gtag.js) - Google Analytics