volatile关键字
1 1 import java.util.concurrent.TimeUnit; 2 2 3 3 /** 4 4 * volatile 5 5 * volatile 比 synchronized 效率高很多 6 6 * 能用volatile就不要用synchronized,很多并发容器都用了volatile 7 7 * volatile并不能保证多个线程共同修改running变量时所带来的不一致问题,也就是说volatile不能替代synchronized 8 8 */ 9 9 public class VolatileTest { 1010 1111 /*volatile*/ boolean running = true; 1212 //对比有无volatile的情况下,执行情况。 1313 1414 void m() { 1515 System.out.println(Thread.currentThread().getName() + " m start ..."); 1616 while (running) { 1717 try { 1818 TimeUnit.SECONDS.sleep(1); //没加volatile,加了休眠,有可能会让线程通信一下。 1919 } catch (InterruptedException e) { 2020 e.printStackTrace(); 2121 } 2222 System.out.println(Thread.currentThread().getName() + " while ..."); 2323 } 2424 System.out.println(Thread.currentThread().getName() + " m end ..."); 2525 } 2626 2727 public static void main(String[] args) { 2828 VolatileTest test = new VolatileTest(); 2929 new Thread(() -> { 3030 test.m(); 3131 }, "线程1").start(); 3232 //new Thread(test :: m, "线程1").start(); //这种写法更简洁 3333 3434 try { 3535 TimeUnit.SECONDS.sleep(2); 3636 } catch (InterruptedException e) { 3737 e.printStackTrace(); 3838 } 3939 4040 test.running = false; //改变running的值,停止死循环 4141 4242 //每个线程都有自己的一块内存区域,线程1拿到running这个值,会去运算,挡住内存running的值发生变化, 4343 // 就没空去主内存读取值, 4444 //当加了volatile这个值,主内存running这个值发生变化时,会通知线程1(缓存过期通知)这个running值发生了变化,再去读一次。 4545 } 4646 4747 } 48 49 1 import java.util.ArrayList; 50 2 import java.util.List; 51 3 52 4 /** 53 5 * volatile并不能保证多个线程共同修改running变量时所带来的不一致问题,也就是说volatile不能替代synchronized 54 6 * 55 7 * synchronized保障原子性和可见性 56 8 */ 57 9 public class VolatileTest1 { 5810 5911 volatile int count = 0; //光可见性是没用的,并不保证原子性 6012 6113 //还是需要加synchronized关键字 6214 void add() { 6315 for(int i=0; i<1000; i++) { 6416 count++; 6517 } 6618 } 6719 6820 public static void main(String[] args) { 6921 7022 VolatileTest1 test = new VolatileTest1(); 7123 List<Thread> threads = new ArrayList<>(10); 7224 //添加线程 7325 for (int i=0; i<10; i++) { 7426 threads.add(new Thread(test :: add, "线程" + i)); 7527 } 7628 //唤醒线程 7729 threads.forEach(t -> t.start()); 7830 7931 threads.forEach(t -> { 8032 try { 8133 t.join(); //主线程等待子线程完成在执行 8234 } catch (InterruptedException e) { 8335 e.printStackTrace(); 8436 } 8537 }); 8638 8739 System.out.println(test.count); 8840 } 8941 9042 }