关键字volatile的作用是强制从公共堆栈中取得变量的值,而不是从线程私有数据栈中取得变量的值。
1.先做一个实验:
    * 源码:   
        public class RunThread extends Thread{
        private boolean isRunning=true;


        public boolean isRunning() {
            return isRunning;
        }


        public void setRunning(boolean running) {
            isRunning = running;
        }


        @Override
        public void run() {
            System.out.println("进入run了");
            while(isRunning == true){


            }
            System.out.println("线程被停止了!");
        }
    }
        public class Run {
        public static void main(String[] args){
            RunThread thread=new RunThread();
            thread.start();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            thread.setRunning(false);
            System.out.println("已经赋值为false");
        }
    }
        运行该代码,发现根本不会停止的,什么原因呢?
        在启动RunThread.java线程是,变量isRunning=true;存在与公共堆栈及线程的私有堆栈中。
        为了运行的效率,线程一直在私有堆栈中取得isRunning的值是true,而更新的却是公共堆栈中
        的isRunning变量值false.所以一直就是死循环的状态。
        改成:
        volatile private boolean isRunning=true;
        就可以了,volatile关键字的作用就是当线程访问isRunning这个变量是,强制性从公共堆栈中进行取值。
2. 关键字synchronized和volatile进行比较:
    * 关键字volatile是线程同步的轻量级实现,所以volatile性能肯定比 synchronized要好,并且 volatile只能
        修饰于变量,而 synchronized可以修饰方法,以及代码块。
    * 多线程访问volatile不会发生阻塞,而 synchronized会发生阻塞
    * volatile能保证数据的可见性,但不能保证原子性;而 synchronized可以保证原子性,也可以间接保证可见性,
        因为它会将私有内存和公有内存中的数据做同步、
    * 关键字volatile解决的是变量在多个线程之间的可见性;而synchronized关键字解决的是多个线程之间访问资源的同步性。
3. volatile 非原子的特性
    * 案例说明volatile不具有原子性和同步性
    eg
        public class MyThread extends Thread {
        volatile public static int count;


        private static void addCount() {
            count++;
            System.out.println("count=" + count);
        }


        @Override
        public void run() {
            addCount();
        }
    }
        public class Run {
        public static void main(String[] args){
            MyThread[] myThreads=new MyThread[100];
            for(int i=0;i<100;i++){
                myThreads[i]=new MyThread();
            }
            for(int i=0;i<100;i++){
                myThreads[i].start();
            }
        }
    }
        运行后发现,好多变量出现了好多次哦,这是因为i++不是原子性的,分为三步:
            * 从内存中取出i的值
            * 计算i的值
            * 将i的值写到内存中
3. synchronized代码块有volatile同步的功能
    * 关键字synchronized可以使多个线程访问同一个资源具有同步性,而且它还具有将线程工作内存中的
        私有变量与公共内存中的变量同步的功能
        eg:
        public class Service {
        private boolean isContinueRun=true;
        public void runMethod(){
            while(isContinueRun==true){
            }
            System.out.println("停下来了!");
        }
        public void stopMethod(){
            isContinueRun=false;
        }
    }
        public class ThreadA extends Thread{
        private Service service;
        public ThreadA(Service service){
            super();
            this.service=service;
        }


        @Override
        public void run() {
            service.runMethod();
        }
    }
        public class ThreadB extends Thread {
        private Service service;
        public ThreadB(Service service){
            super();
            this.service=service;
        }


        @Override
        public void run() {
            service.stopMethod();
        }
    }
        public class Run {
        public static void main(String[] args){
            Service service=new Service();
            ThreadA a=new ThreadA(service);
            a.start();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ThreadB b=new ThreadB(service);
            b.start();
            System.out.println("已经发起停止的命令了!");
        }
    }
    该代码并不能停止,具体前面说了,没有可见性,前面是用volatile实现的,现在用synchronized
    Service代码做如下更改:
        public class Service {
        private boolean isContinueRun=true;
        public void runMethod(){
            String anyString=new String();
            while(isContinueRun==true){
                synchronized (anyString){
                    
                }
            }
            System.out.println("停下来了!");
        }
        public void stopMethod(){
            isContinueRun=false;
        }
    }
        现在可以了,s关键字synchronized可以保证在同一时刻,只有一个线程可以执行某一个方法或某一个代码块。
        它包含两个特征:互斥性和可见性。同步synchronized不仅可以解决一个线程看到对象处于不一致的状态,还
        可以保证进入同步方法或者同步代码块的每个线程,都看到由同一个锁保护之前所有的修改效果。(书上原话= =)
        在我的理解,如果锁加在isContinueRun上是可以理解的,为了同步,肯定会强制用公共堆栈,但是加在anyString上= =,
        anyString被强制公共堆栈并没有什么卵用= =,在我的理解是,加了synchronized关键词,在未执行到指定代码之前,
        虚拟机并不知道锁在哪个对象上,为了让锁的对象永远保持一个,保证同步,只要类中出现synchronized关键字,就把
        所有对象的存取指定在公共堆栈。(个人看法)。