当多个线程操做同一个变量时,每一个线程都会将该变量拷贝一份到本身工做内存中,而后线程完成操做以后,将变量写回主内存。所以可见性就是一个线程在修改变量以后,回通知其余线程,告知改变量已经被修改了。
首先建立一个资源类java
class MyData { volatile int number = 0; public void setNumber () { this.number = 60; } public void numberPlus() { this.number++; } } // 多线程下测试 public static void main(String[] args) { MyData myData = new MyData(); new Thread(() -> { System.out.println(myData.number); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } myData.setNumber(); System.out.println(myData.number); }, "AAA").start();; while(myData.number == 0) { } }
当使用 volatile
修饰 number
以后,程序回输出 0 和 60 以后执行完成退出。
当没有使用 volatile
修饰 number
,程序回输出 0 和 60 以后一直保持执行(死循环),不退出。
由此能够看出,volatile
修饰的变量在修改后,回通知其余线程,保证可见性。多线程
class MyData { volatile int number = 0; public void setNumber () { this.number = 60; } public void numberPlus() { this.number++; } AtomicInteger atomicInteger = new AtomicInteger(); // 默认为0 public void atomicAdd() { atomicInteger.getAndIncrement(); } } public static void main(String[] args) { MyData myData = new MyData(); for(int i=0; i<20; i++) { new Thread(() -> { for(int j=0; j<1000; j++) { myData.numberPlus(); myData.atomicAdd(); } }, String.valueOf(i)).start();; } while(Thread.activeCount() >2) { Thread.yield(); } System.out.println(myData.number); System.out.println(myData.atomicInteger); }
程序输出 number
的值小于20000,atomicIntege
r等于20000。
由于 volatile
不保证原子性,因此在多线程下操做 number
会出现值被覆盖的问题,也就是一个线程尚未完成++,另外一个线程就取出了 number
进行++, 最后致使值小于了 20000。
解决 volatile
原子性问题,可使用 AtomicInteger
。性能
为了提升性能,编译器和处理器经常会进行指令重排,在多线程环境下,因为指令重排,致使代码的执行顺序和咱们书写代码顺序不一致,最终变量可否保持一致是没法肯定的,结果没法预测。测试