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();
		
	}