首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

transient-JAVA成长之路

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

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

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

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

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

java关键字Transient

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

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

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

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

importjava.util.Date;

publicclassLoggingInfoimplementsjava.io.Serializable {

privateDate loggingDate =newDate();

privateString uid;

privatetransientString pwd;

LoggingInfo(String user, String password) {

uid=user;

pwd=password;

}

publicString 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)它 ,然后将这个串行化对象写如磁盘。

packagecom.wms.test;

importjava.io.FileInputStream;

importjava.io.FileOutputStream;

importjava.io.ObjectInputStream;

importjava.io.ObjectOutputStream;

publicclassTestTransientimplementsjava.io.Serializable {

publicstaticvoidmain(String[] args) {

LoggingInfo logInfo=newLoggingInfo("MIKE", "MECHANICS");

System.out.println(logInfo.toString());

try{

ObjectOutputStream o=newObjectOutputStream(

newFileOutputStream("logInfo.out"));

o.writeObject(logInfo);

o.close();

}catch(Exception e) {

//deal with exception

}

//To read the object back, we can write

try{

ObjectInputStream in=newObjectInputStream(

newFileInputStream("logInfo.out"));

LoggingInfo logInfoIn=(LoggingInfo)in.readObject();

System.out.println(logInfoIn.toString());

}catch(Exception e) {

//deal with exception

}

}

}

输出结果:

logon info:

user: MIKE

logging date : Wed Apr13 22:13:44 CST 2016

password: MECHANICS

logon info:

user: MIKE

logging date : Wed Apr13 22:13:44 CST 2016

password: NOT SET

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

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

publicclassGuestLoggingInfoimplementsjava.io.Serializable {

privateDate loggingDate =newDate();

privateString uid;

privatetransientString pwd;

GuestLoggingInfo() {

uid= "guest";

pwd= "guest";

}

publicString toString() {

//same as above

}

}

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

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20200615A0AK3000?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券