`

java volatile and transient

    博客分类:
  • java
阅读更多

Volatile

Volatile修饰的成员变量在每次被线程访问时,都强迫从主内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到主内存。

这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。

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

这样当多个线程同时与某个对象交互时,就必须要注意到要让线程及时的得到共享成员变量的变化。 而volatile关键字就是提示VM:对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。

使用建议:在两个或者更多的线程访问的成员变量上使用volatile。当要访问的变量已在synchronized代码块中,或者为常量时,不必使用。 由于使用volatile屏蔽掉了VM中必要的代码优化,所以在效率上比较低,因此一定在必要时才使用此关键字。

Transient

Transient修饰的成员变量不会被序列化

Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,我们不想用serialization机制来保存它。 为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。

transient是Java语言的关键字,用来表示一个域不是该对象串行化的一部分。当一个对象被串行化的时候,transient型变量的值不包括在串行化的表示中,然而非transient型的变量是被包括进去的。 注意static变量也是可以串行化的

example

首先,让我们看一些Java serialization的代码:

  1. public class LoggingInfo implements java.io.Serializable 
  2.     private Date loggingDate = new Date(); 
  3.     private String uid; 
  4.     private transient String pwd; 
  5.  
  6.     LoggingInfo(String user, String password) 
  7.     { 
  8.         uid = user; 
  9.         pwd = password; 
  10.     } 
  11.     public String toString() 
  12.     { 
  13.         String password=null
  14.         if(pwd == null
  15.         { 
  16.             password = "NOT SET"
  17.         } 
  18.         else 
  19.         { 
  20.             password = pwd; 
  21.         } 
  22.         return "logon info: \\n   " + "user: " + uid + 
  23.                 "\\n   logging date : " + loggingDate.toString() + 
  24.                 "\\n   password: " + password; 
  25.     } 
  26. }

现在我们创建一个这个类的实例,并且串行化(serialize)它 ,然后将这个串行化对象写如磁盘。

  1. class Scratch { 
  2.     public static void main(String[] args) { 
  3.         LoggingInfo logInfo = new LoggingInfo("MIKE""MECHANICS"); 
  4.         System.out.println(logInfo.toString()); 
  5.         try { 
  6.             ObjectOutputStream o = new ObjectOutputStream( 
  7.                     new FileOutputStream("logInfo.out")); 
  8.             o.writeObject(logInfo); 
  9.             o.close(); 
  10.         } catch (Exception e) { 
  11.             //deal with exception    
  12.         } 
  13.         //To read the object back, we can write 
  14.  
  15.         try { 
  16.             ObjectInputStream in = new ObjectInputStream( 
  17.                     new FileInputStream("logInfo.out")); 
  18.             LoggingInfo logInfo = (LoggingInfo) in.readObject(); 
  19.             System.out.println(logInfo.toString()); 
  20.         } catch (Exception e) { 
  21.             //deal with exception 
  22.         } 
  23.     } 
  24. }

如果我们运行这段代码,我们会注意到从磁盘中读回(read——back (de-serializing))的对象打印password为"NOT SET"。这是当我们定义pwd域为transient时,所期望的正确结果。

现在,让我们来看一下粗心对待transient域可能引起的潜在问题。假设我们修改了类定义,提供给transient域一个默认值,代码如下:

  1. public class GuestLoggingInfo implements java.io.Serializable 
  2.     private Date loggingDate = new Date(); 
  3.     private String uid; 
  4.     private transient String pwd; 
  5.  
  6.     GuestLoggingInfo() 
  7.     { 
  8.         uid = "guest"
  9.         pwd = "guest"
  10.     } 
  11.     public String toString() 
  12.     { 
  13.         //same as above    
  14.     } 
  15. }

现在,如果我们穿行化GuestLoggingInfo的一个实例,将它写入磁盘,并且再将它从磁盘中读出,我们仍然看到读回的对象打印password 为 "NOT SET"。 当从磁盘中读出某个类的实例时,实际上并不会执行这个类的构造函数, 而是载入了一个该类对象的持久化状态,并将这个状态赋值给该类的另一个对象。

分享到:
评论

相关推荐

    Learn.Java.for.Android.Development_Apress.2010+src

    Continuing, you investigate strictfp, class literals, synchronized, volatile, the enhanced for loop statement, autoboxing/unboxing, and transient fields. The book also briefly presents most (if not ...

    Java并发编程-并发容器1

    1. **table**: `transient volatile Node,V>[] table` 是存储Node的数组,作为ConcurrentHashMap的数据容器。采用懒加载,首次插入数据时初始化,数组大小为2的幂次方。 2. **nextTable**: `transient volatile Node...

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

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

    java面试必会200题.docx

    ### Java面试必会知识点解析 #### 一、基本概念 1. **操作系统中heap和stack的区别** - **栈(stack)**:是一种线性数据结构,遵循先进后出(FILO)的原则。主要用于存储局部变量、函数参数等。栈的空间由操作系统...

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

    在 java 语言中,Java 程序的基本单位是类,也就是说:一个 Java 程序是由多个类组成 的。定义一个类与定义一个数据类型是有区别的。在程序设计语言中,把定义数据类型的能 力作为一种很重要的能力来对待。在面向...

    整理后java开发全套达内学习笔记(含练习)

    volatile (关键字) 不稳定的['vɒlәtail] while (关键字) 循环语句。 当...的时候 [hwail] ORACLE_SID=oral10g\ --变局部变量 export ORACLE_SID --变全局变量 unset ORACLE_SID --卸载环境变量 ORACLE_HOME=...

    java1-6章测试题目.pdf

    40. **成员修饰符**:public、private、protected、static、final、volatile、transient等,用于控制访问权限和特性。 41. **类、抽象类、接口间的关系**:类可以继承类或实现接口,抽象类可以被类继承,接口可以被...

    JAVA基础 第4章继承与多态_练习题_200910.pdf

    题目中询问非访问控制修饰符,它们包括`final`、`abstract`、`static`、`transient`、`volatile`等。 总结这些题目,我们可以看到Java的包管理、类的继承、多态性、访问控制、构造器的使用以及方法覆盖等关键概念。...

    java基础语法讲解上集,适合初级人员入门学习

    - `native`、`strictfp`、`transient`、`volatile`、`assert`:这些关键字用于特定场景下的高级功能。 #### 2. 标识符(Identifiers) 标识符是在程序中用于命名变量、类、方法等元素的名称。在Java中,标识符必须...

    Java进阶知识点汇总.pdf

    - **transient**:用于声明变量不参与序列化过程,常用于对象中包含临时状态信息的情况。 - **volatile**:用于修饰共享变量,确保多线程环境中的可见性和有序性,但不保证原子性。 - **synchronized**:用于实现...

    王者归来之JAVA2核心技术第1卷.基础知识7thJoin4.pdf

    - `volatile`:确保一个域可以被多个线程访问。 - `while`:一种循环语句。 ### 关键特性与新特性 文档中还介绍了JDK5.0中引入的几个重要的新特性,以及如何在JDK1.4下进行兼容性修改: #### B.1 增强的for循环...

    类文件结构1

    访问标志用于指示字段的访问权限和特性,如public、private、protected、static、final、volatile和transient。 方法表结构与字段表类似,但还包含了方法的访问标志、名称索引、描述符索引、属性计数和属性列表。...

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

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

    sesvc.exe 阿萨德

    * for keySet() and values(). */ transient Set,V&gt;&gt; entrySet; /** * The number of key-value mappings contained in this map. */ transient int size; 和 1.7 大体上都差不多,还是有几个重要的区别: ...

    百度持续交付项目组面试题

    **volatile关键字**用于标记变量的状态,当一个变量被声明为volatile时,任何对该变量的读写操作都直接发生在主存中,因此任何线程对该变量的修改都能被其他线程立即感知。 **线程安全**是指多个线程并发访问同一个...

Global site tag (gtag.js) - Google Analytics