1 transient
加了该关键字的属性,不会被序列化
换句话说,这个字段仅存于调用者内存中,而不会写到磁盘里持久化。
序列化原理:将待序列化的对象的信息写入到磁盘或者网络流中。序列化中的引用会进行“深度复制”,并且如果两个对象有共同的引用对象,且两个对象都写入同一个流中,哪个该引用对象不会重复创建,只会创建一次,并还原到虚拟机后引用的还是同一个对象。但是,写入不同的流中,那么两次创建的是完全不同的还原对象。
2 volatile
每个线程访问堆中对象时,将堆中对象load到线程本地内存中,建立一个变量副本,之后线程就不再和对象在堆变量的值上有任何关系,而是直接修改副本变量值。(换句话说,就是副本中变量的值如何修改也不会影响到其先前对象的值)。
修改完毕之后,自动把线程变量副本的值写到对象在堆的变量中。这样堆中对象的值就产生李变化。但这些操作不是原子性的。
使用volatile修饰变量,JVM只是保证从内存加载到线程工作内存中的值是罪行的。因此,即使使用volatile还是会存在并发情况。
比如:
volatile int a=0;
线程A和线程B同时执行
a++;
此时线程A拿到a的最新值0,线程B也拿到最新值0;但是,A执行a++后,值为1,B也同样计算到a=1,他们再同时写回到堆内存,使得最后a的值为1,并不为2(当然,这只是理论上的情况,实际上如果两个线程只对变量进行简单的操作比如++或--,并不会出现以上的情况,因为线程执行的时间很短,只有在进行较复杂的计算时才会出现以上情况:如下代码:)。
public class testVolatile {
volatile int a=0;
public static void main(String[] args) {
// TODO Auto-generated method stub
testVolatile v=new testVolatile();
int count=0;
while(count<100){
v.test();
v.test();
count++;
}
}
public void test(){
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
int count=0;
while(count<10){
count++;
a++;
System.out.println(a);
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
int count=0;
while(count<10){
count++;
a++;
System.out.println(a);
}
}
}).start();
}