本文共 3423 字,大约阅读时间需要 11 分钟。
关键字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关键字,就把 所有对象的存取指定在公共堆栈。(个人看法)。转载地址:http://umjqi.baihongyu.com/