目录java
代码解析:新起一个子线程执行m()方法,1秒后主线程将b置为false,子线程是否会中止执行死循环while(b){},打印“end”缓存
package com.bernardlowe.concurrent.t01; import java.util.concurrent.TimeUnit; public class Test_09 { boolean b = true; void m(){ System.out.println("start"); while(b){} System.out.println("end"); } public static void main(String[] args) { final Test_09 t = new Test_09(); new Thread(new Runnable() { @Override public void run() { t.m(); } }).start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } t.b = false; } }
结果:1秒钟事后并不会中止执行死循环while(b){},打印“end”
这时候,若是将boolean b = true;这段代码前加一个volatile关键字
即volatile boolean b = true;
,就会达到预想中的效果安全
思考:为何加上这个关键字,其余线程就会读取到已经改变的变量的值了?ide
是由于在CPU计算过程当中,会将计算过程须要的数据加载到CPU计算缓存中,当CPU计算中断时,有可能刷新缓存,从新读取内存中的数据。在线程运行的过程当中,若是某变量被其余线程修改,可能形成数据不一致的状况,从而致使结果错误。
而volatile修饰的变量是线程可见的,当JVM解释volatile修饰的变量时,会通知CPU,在计算过程当中,每次使用变量参与计算时,都会检查内存中的数据是否发生变化,而不是一直使用CPU缓存中的数据,能够保证计算结果的正确。atom
可是这样还有一个问题,volatile只能保证可见性,不能保证原子性线程
下面再看一个示例:
预期结果:起10个线程,每一个线程都对count增长10000,预期结果为count=100000code
package com.bernardlowe.concurrent.t01; import java.util.ArrayList; import java.util.List; public class Test_10 { volatile int count = 0; /*synchronized*/ void m(){ for(int i = 0; i < 10000; i++){ count++; } } public static void main(String[] args) { final Test_10 t = new Test_10(); List<Thread> threads = new ArrayList<>(); for(int i = 0; i < 10; i++){ threads.add(new Thread(new Runnable() { @Override public void run() { t.m(); } })); } for(Thread thread : threads){ thread.start(); } for(Thread thread : threads){ try { thread.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println(t.count); } }
但结果并非blog
缘由是volatile只是通知底层计算时,CPU检查内存数据,而不是让一个变量在多个线程中同步。内存
这时候能够给m()方法增长一个synchronized关键字,能够达到预期的效果,即synchronized void m()
rem
还有另外一种方法能够保证原子性,在上面代码将count声明为AtomicInteger原子操做,结果仍然是100000
// 其中的每一个方法都是原子操做。能够保证线程安全。 AtomicInteger count = new AtomicInteger(0); void m(){ for(int i = 0; i < 10000; i++){ count.incrementAndGet(); } }
这里不单单可声明Integer类型,java.util.concurrent.atomic包里面还有其余类型的