volatile关键字
1 import java.util.concurrent.TimeUnit; 2 3 /** 4 * volatile 5 * volatile 比 synchronized 效率高很多 6 * 能用volatile就不要用synchronized,很多并发容器都用了volatile 7 * volatile并不能保证多个线程共同修改running变量时所带来的不一致问题,也就是说volatile不能替代synchronized 8 */ 9 public class VolatileTest { 10 11 /*volatile*/ boolean running = true; 12 //对比有无volatile的情况下,执行情况。 13 14 void m() { 15 System.out.println(Thread.currentThread().getName() + " m start ..."); 16 while (running) { 17 try { 18 TimeUnit.SECONDS.sleep(1); //没加volatile,加了休眠,有可能会让线程通信一下。 19 } catch (InterruptedException e) { 20 e.printStackTrace(); 21 } 22 System.out.println(Thread.currentThread().getName() + " while ..."); 23 } 24 System.out.println(Thread.currentThread().getName() + " m end ..."); 25 } 26 27 public static void main(String[] args) { 28 VolatileTest test = new VolatileTest(); 29 new Thread(() -> { 30 test.m(); 31 }, "线程1").start(); 32 //new Thread(test :: m, "线程1").start(); //这种写法更简洁 33 34 try { 35 TimeUnit.SECONDS.sleep(2); 36 } catch (InterruptedException e) { 37 e.printStackTrace(); 38 } 39 40 test.running = false; //改变running的值,停止死循环 41 42 //每个线程都有自己的一块内存区域,线程1拿到running这个值,会去运算,挡住内存running的值发生变化, 43 // 就没空去主内存读取值, 44 //当加了volatile这个值,主内存running这个值发生变化时,会通知线程1(缓存过期通知)这个running值发生了变化,再去读一次。 45 } 46 47 }
1 import java.util.ArrayList; 2 import java.util.List; 3 4 /** 5 * volatile并不能保证多个线程共同修改running变量时所带来的不一致问题,也就是说volatile不能替代synchronized 6 * 7 * synchronized保障原子性和可见性 8 */ 9 public class VolatileTest1 { 10 11 volatile int count = 0; //光可见性是没用的,并不保证原子性 12 13 //还是需要加synchronized关键字 14 void add() { 15 for(int i=0; i<1000; i++) { 16 count++; 17 } 18 } 19 20 public static void main(String[] args) { 21 22 VolatileTest1 test = new VolatileTest1(); 23 List<Thread> threads = new ArrayList<>(10); 24 //添加线程 25 for (int i=0; i<10; i++) { 26 threads.add(new Thread(test :: add, "线程" + i)); 27 } 28 //唤醒线程 29 threads.forEach(t -> t.start()); 30 31 threads.forEach(t -> { 32 try { 33 t.join(); //主线程等待子线程完成在执行 34 } catch (InterruptedException e) { 35 e.printStackTrace(); 36 } 37 }); 38 39 System.out.println(test.count); 40 } 41 42 }