Volatile和Transient

来源:互联网 发布:商城源码怎么去后门 编辑:程序博客网 时间:2024/05/16 06:41

Volatile:

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

  
  Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,我们不想   
  用serialization机制来保存它。为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。   
  transient是Java语言的关键字,用来表示一个域不是该对象串行化的一部分。当一个对象被串行化的时候,transient型变量的值不包括在串行化的表示中,然而非transient型的变量是被包括进去的。  
注意static变量也是可以串行化的 
  
首先,让我们看一些Java serialization的代码:   

复制代码
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;       }   }   
复制代码

 

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

复制代码
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}   
复制代码

 

  如果我们运行这段代码,我们会注意到从磁盘中读回(read——back (de-serializing))的对象打印password为"NOT SET"。这是当我们定义pwd域为transient时,所期望的正确结果。   
  现在,让我们来看一下粗心对待transient域可能引起的潜在问题。假设我们修改了类定义,提供给transient域一个默认值,   
代码如下:   
  

复制代码
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        }   }   
复制代码

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

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 网贷半夜打电话怎么办 拼多多聊天违规怎么办 珍爱网骚扰电话怎么办 打暑假工被骗怎么办 时时彩被骗了怎么办 急用钱逾期半年怎么办 征信花了急用钱怎么办 信用卡未通过审核怎么办 苹果想更新系统怎么办 用钱宝恶意骚扰怎么办 乐贷款登录不了怎么办 急需6000元怎么办黑户 信而富绑卡失败怎么办 回访电话说错了怎么办 乐贷款逾期一天怎么办 被贷款公司骚扰怎么办 趣店账户异常怎么办 指还王要还款下载不了怎么办 随心花账户异常怎么办 账号已被锁定怎么办 哈罗单车被警告怎么办 禁止安装拼多多怎么办 该用户行为异常怎么办 设备被禁止登录怎么办 你的设备被禁封怎么办 监控显示未配置怎么办 监控显示不在线怎么办 兔聊认证不通过怎么办 高考成绩被屏蔽怎么办 百合号码换了怎么办 微粒贷还款限额怎么办 秒白条扣款失败怎么办 信用卡逾期没还怎么办 催收发侮辱短信怎么办? 快贷还清后被拒怎么办 任信用还不起怎么办 信用飞额度抢光怎么办 装修工钱要不回怎么办 装修客户不给钱怎么办 公司赖账不给怎么办 欠钱不还还把我设置黑名单怎么办