天天看点

java volatile 和Transient 关键字

java volatile 和Transient 关键字

java关键字volatile

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

java volatile 和Transient 关键字
java volatile 和Transient 关键字

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

java volatile 和Transient 关键字
java volatile 和Transient 关键字

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

java volatile 和Transient 关键字
java volatile 和Transient 关键字

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

java volatile 和Transient 关键字
java volatile 和Transient 关键字

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

java volatile 和Transient 关键字
java volatile 和Transient 关键字

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

java volatile 和Transient 关键字
java volatile 和Transient 关键字

java关键字transient   

java volatile 和Transient 关键字
java volatile 和Transient 关键字

转自http://horst.sun.blog.163.com/blog/static/348849612007614494492/   

java volatile 和Transient 关键字
java volatile 和Transient 关键字

翻译自http://www.devx.com/tips/tip/13726。   

java volatile 和Transient 关键字
java volatile 和Transient 关键字

java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,我们不想   

java volatile 和Transient 关键字

用serialization机制来保存它。为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。   

java volatile 和Transient 关键字

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

注意static变量也是可以串行化的 

java volatile 和Transient 关键字
java volatile 和Transient 关键字

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

java volatile 和Transient 关键字

public class logginginfo implements java.io.serializable   

java volatile 和Transient 关键字

{   

java volatile 和Transient 关键字

    private date loggingdate = new date();   

java volatile 和Transient 关键字

    private string uid;   

java volatile 和Transient 关键字

    private transient string pwd;   

java volatile 和Transient 关键字
java volatile 和Transient 关键字

    logginginfo(string user, string password)   

java volatile 和Transient 关键字

    {   

java volatile 和Transient 关键字

        uid = user;   

java volatile 和Transient 关键字

        pwd = password;   

java volatile 和Transient 关键字

    }   

java volatile 和Transient 关键字

    public string tostring()   

java volatile 和Transient 关键字
java volatile 和Transient 关键字

        string password=null;   

java volatile 和Transient 关键字

        if(pwd == null)   

java volatile 和Transient 关键字

        {   

java volatile 和Transient 关键字

        password = "not set";   

java volatile 和Transient 关键字

        }   

java volatile 和Transient 关键字

        else  

java volatile 和Transient 关键字
java volatile 和Transient 关键字

            password = pwd;   

java volatile 和Transient 关键字
java volatile 和Transient 关键字

        return "logon info: \n   " + "user: " + uid +   

java volatile 和Transient 关键字

            "\n   logging date : " + loggingdate.tostring() +   

java volatile 和Transient 关键字

            "\n   password: " + password;   

java volatile 和Transient 关键字
java volatile 和Transient 关键字

}   

java volatile 和Transient 关键字
java volatile 和Transient 关键字

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

java volatile 和Transient 关键字
java volatile 和Transient 关键字

logginginfo loginfo = new logginginfo("mike", "mechanics");   

java volatile 和Transient 关键字

system.out.println(loginfo.tostring());   

java volatile 和Transient 关键字

try  

java volatile 和Transient 关键字
java volatile 和Transient 关键字

   objectoutputstream o = new objectoutputstream(   

java volatile 和Transient 关键字

                new fileoutputstream("loginfo.out"));   

java volatile 和Transient 关键字

   o.writeobject(loginfo);   

java volatile 和Transient 关键字

   o.close();   

java volatile 和Transient 关键字
java volatile 和Transient 关键字

catch(exception e) {//deal with exception}   

java volatile 和Transient 关键字
java volatile 和Transient 关键字

to read the object back, we can write   

java volatile 和Transient 关键字
java volatile 和Transient 关键字
java volatile 和Transient 关键字
java volatile 和Transient 关键字

   objectinputstream in =new objectinputstream(   

java volatile 和Transient 关键字

                new fileinputstream("loginfo.out"));   

java volatile 和Transient 关键字

   logginginfo loginfo = (logginginfo)in.readobject();   

java volatile 和Transient 关键字

   system.out.println(loginfo.tostring());   

java volatile 和Transient 关键字
java volatile 和Transient 关键字
java volatile 和Transient 关键字
java volatile 和Transient 关键字

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

java volatile 和Transient 关键字

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

java volatile 和Transient 关键字

代码如下:   

java volatile 和Transient 关键字
java volatile 和Transient 关键字

public class guestlogginginfo implements java.io.serializable   

java volatile 和Transient 关键字
java volatile 和Transient 关键字
java volatile 和Transient 关键字
java volatile 和Transient 关键字
java volatile 和Transient 关键字
java volatile 和Transient 关键字

    guestlogginginfo()   

java volatile 和Transient 关键字
java volatile 和Transient 关键字

        uid = "guest";   

java volatile 和Transient 关键字

        pwd = "guest";   

java volatile 和Transient 关键字
java volatile 和Transient 关键字

    public string tostring()       {   

        //same as above   

     }   

现在,如果我们穿行化guestlogginginfo的一个实例,将它写入磁盘,并且再将它从磁盘中读出,我们仍然看到读回的对象打印password 为 "not set"。当从磁盘中读出某个类的实例时,实际上并不会执行这个类的构造函数,   

而是载入了一个该类对象的持久化状态,并将这个状态赋值给该类的另一个对象。