以前没有弄懂validate和synchronized,借此新开博之际记录下。
volatile(不稳定):java关键字用来修饰变量,不可用来修饰方法。
在java语法中对于变量值读写的操作,除了long和double都是原子性操作。其原因是在一些jvm中处理的原子为4bytes,基本类型(jvm处理2种类型一种是基本类型primitive,一种是引用类型reference)一般都是4bytes,long和double是8bytes。jvm对于数据的操作是遵循原子性的,如果不以volatile修饰long和double,如果多线程访问该变量,由于long操作的整体非原子性而导致结果混乱。所以long和double在读写的时候都需要被修饰volatile,而其他的类型在读写的时候则不需要被volatile修饰。比如:int,一个线程写入4,另一个写入5. 最后肯定是4或者5.而 long型,可能就是个乱七八糟的数值了。
在当前的jvm内存模型下,线程可以把变量放在本地内存中,而不是直接写到主存中。但是在别的线程中就有可能在寄存器中读取而主存中的数据已经改变,因此产生了不同步的情况。这个也是用volatile的另一个原因,经过volatile修饰的变量都要在主存中进行读取。当volatile修饰的变量被线程访问的时候,jvm会强制线程从主存中读取;当变量的值改变的时候,jvm会强制写入主存。另外:volatile修饰的变量会屏蔽掉jvm中必要的代码优化,所以在效率上会稍微低一点。
以上理论全部都建立在原子性操作的情况下,如果非原子性操作,例如n++,n=n+1等,则需要用synchronized进行修饰。
volatile修饰的变量,操作中含有非原子性操作:
public class ThreadTest extends Thread{ private volatile static int num=0; public void run(){ for(int i=0;i<10;i++){ num++; /*try { this.sleep(3); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); }*/ } } public static void main(String[] args) { // TODO Auto-generated method stub byte m=1; m=(byte) (m>>1); Thread[] threads=new Thread[100]; for(int i=0;i<threads.length;i++){ threads[i]=new ThreadTest(); } for(int i=0;i<threads.length;i++){ threads[i].start(); }
System.out.println("The result is "+ThreadTest.num);}}for(int i=0;i<threads.length;i++){ threads[i].join(); }
————————————————————————————————
以上返回:The result is 986
用synchronized修饰
输出结果:1000public class ThreadTest extends Thread{ private volatile static int num=0; public static synchronized void plus(){ num++; } public void run(){ for(int i=0;i<10;i++){ plus(); //num++; try { this.sleep(3); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public static void main(String[] args) throws InterruptedException { // TODO Auto-generated method stub Thread[] threads=new Thread[100]; for(int i=0;i<threads.length;i++){ threads[i]=new ThreadTest(); } for(int i=0;i<threads.length;i++){ threads[i].start(); } for(int i=0;i<threads.length;i++){ threads[i].join(); } System.out.println("The result is "+ThreadTest.num); } }