java多线程之volatile关键字
2015-11-08 00:00
288 查看
在java线程并发处理中,关键字volatile的主要作用是使变量在多个线程间可见。那么volatile到底该怎么用了?我们首先来看一段代码:
此段代码如果运行,我们可以发现线程能正常停止。如果代码运行在-server服务器模式中64bit的JVM上时,会出现死循环。解决的方案是用
volatile关键字。关键字volatile的作用是强制从公共堆栈取得变量的值,而不是从线程私有数据栈中取得变量的值。
我们将代码改造下:
使用了volatile关键字增加了实例变量在多线程之间的可见性。但volatile关键字最致命的缺点是不支持原子性。
关键字synchronized跟volatile进行一下比较:
关键字volatile是线程同步的轻量级实现,所以volatile性能肯定比synchronized要好,并且volatile只能修饰变量,而synchronized可以修饰方法,以及代码块。随着JDK新版本的发布,synchronized关键字执行效率打打的提高,在开发中使用synchronized还是比较多的。
多线程访问volatile不会发生堵塞,而synchronized可能会出现堵塞。
volatile能保证数据的可见性,但不能保证原子性;而synchronized可以保证原子性,也可以间接保证可见性,因为它会将私有内存和公共内存中的数据做了同步。
关键字volatile解决的是变量在多个线程之间的可见性;而synchronized关键字解决的是多个线程之间访问资源的同步性。
volatile非原子的特性
关键字volatile主要使用的场合是在多线程中可以感知实例变量被更改了,并且可以获得最新的值使用,也就是用多线程读取共享变量时可以获得最新的值。
关键字volatile提示线程每次从共享内存中读取变量,而不是从私有内存中读取,这样就保证了同步数据的可见性。但需要注意的是:如果修改实例变量中的数据,比如i++,也就是i=i+1,这样的操作并不是一个原子操作,也就是非线程安全的。表达式i++的实际操作步骤是:
从内存中读取i的值;
计算i的值;
将i的值写入到内存中。
所以说volatile本身并不处理数据的原子性,而是强制对数据读写及时影响到主内存的。
由上我们可以得出结论:
synchronized关键字是防止多个线程同时执行一段代码,那么就会很影响程序执行效率,而volatile关键字在某些情况下性能要优于synchronized,但是要注意volatile关键字是无法替代synchronized关键字的,因为volatile关键字无法保证操作的原子性。通常来说,使用volatile必须具备以下2个条件:
1)对变量的写操作不依赖于当前值
2)该变量没有包含在具有其他变量的不变式中
实际上,这些条件表明,可以被写入 volatile 变量的这些有效值独立于任何程序的状态,包括变量的当前状态。
事实上,我的理解就是上面的2个条件需要保证操作是原子性操作,才能保证使用volatile关键字的程序在并发时能够正确执行。
Java中使用volatile的场景:
版权声明:本文为博主原创文章,未经博主允许不得转载。
public class MyThread1 implements Runnable { private boolean istag = true; public boolean isIstag() { return istag; } public void setIstag(boolean istag) { this.istag = istag; } public void print() { try { while (istag) { System.out.println("print()线程名称是:"+Thread.currentThread().getName()); Thread.sleep(1000); } } catch (Exception e) { } } @Override public void run() { print(); } }
public class MyThread { public static void main(String[] args) { MyThread1 m=new MyThread1(); new Thread(m).start(); System.out.println("我要停止循环-->"+Thread.currentThread().getName()); m.setIstag(false); } }
此段代码如果运行,我们可以发现线程能正常停止。如果代码运行在-server服务器模式中64bit的JVM上时,会出现死循环。解决的方案是用
volatile关键字。关键字volatile的作用是强制从公共堆栈取得变量的值,而不是从线程私有数据栈中取得变量的值。
我们将代码改造下:
public class MyThread1 extends Thread { private volatile boolean istag = true; public boolean isIstag() { return istag; } public void setIstag(boolean istag) { this.istag = istag; } @Override public void run() { System.out.println("进入run()===="); while (istag) { System.out.println("线程名称是:"+Thread.currentThread().getName()); } System.out.println("线程被停止===="); } }
使用了volatile关键字增加了实例变量在多线程之间的可见性。但volatile关键字最致命的缺点是不支持原子性。
关键字synchronized跟volatile进行一下比较:
关键字volatile是线程同步的轻量级实现,所以volatile性能肯定比synchronized要好,并且volatile只能修饰变量,而synchronized可以修饰方法,以及代码块。随着JDK新版本的发布,synchronized关键字执行效率打打的提高,在开发中使用synchronized还是比较多的。
多线程访问volatile不会发生堵塞,而synchronized可能会出现堵塞。
volatile能保证数据的可见性,但不能保证原子性;而synchronized可以保证原子性,也可以间接保证可见性,因为它会将私有内存和公共内存中的数据做了同步。
关键字volatile解决的是变量在多个线程之间的可见性;而synchronized关键字解决的是多个线程之间访问资源的同步性。
volatile非原子的特性
public class MyThread1 extends Thread { private volatile static int count; public void addCount(){ for (int i = 0; i < 100; i++) { count++; } System.out.println("count="+count); } @Override public void run() { addCount(); } }
public class RunTest { public static void main(String[] args){ MyThread1[] myArray=new MyThread1[100]; for (int i = 0; i < 100; i++) { myArray[i]=new MyThread1(); } for (int i = 0; i < 100; i++) { myArray[i].start(); } } }
public class MyThread1 extends Thread { private static int count; //需要加static,才达到同步效果 public synchronized static void addCount(){ for (int i = 0; i < 100; i++) { count++; } System.out.println("count="+count); } @Override public void run() { addCount(); } }
关键字volatile主要使用的场合是在多线程中可以感知实例变量被更改了,并且可以获得最新的值使用,也就是用多线程读取共享变量时可以获得最新的值。
关键字volatile提示线程每次从共享内存中读取变量,而不是从私有内存中读取,这样就保证了同步数据的可见性。但需要注意的是:如果修改实例变量中的数据,比如i++,也就是i=i+1,这样的操作并不是一个原子操作,也就是非线程安全的。表达式i++的实际操作步骤是:
从内存中读取i的值;
计算i的值;
将i的值写入到内存中。
所以说volatile本身并不处理数据的原子性,而是强制对数据读写及时影响到主内存的。
由上我们可以得出结论:
synchronized关键字是防止多个线程同时执行一段代码,那么就会很影响程序执行效率,而volatile关键字在某些情况下性能要优于synchronized,但是要注意volatile关键字是无法替代synchronized关键字的,因为volatile关键字无法保证操作的原子性。通常来说,使用volatile必须具备以下2个条件:
1)对变量的写操作不依赖于当前值
2)该变量没有包含在具有其他变量的不变式中
实际上,这些条件表明,可以被写入 volatile 变量的这些有效值独立于任何程序的状态,包括变量的当前状态。
事实上,我的理解就是上面的2个条件需要保证操作是原子性操作,才能保证使用volatile关键字的程序在并发时能够正确执行。
Java中使用volatile的场景:
package com.ztz.myThread; public class Singleton { private volatile static Singleton instance = null; private Singleton() { } public static Singleton getInstance(){ if(instance==null){ synchronized (Singleton.class) { if(instance==null) instance = new Singleton(); } } return instance; } }
版权声明:本文为博主原创文章,未经博主允许不得转载。
相关文章推荐
- 剖析springmvc之HelloWorld
- springmvc上传图片并显示图片--支持多图片上传
- java多线程之synchronized
- springmvc使用实体参数和ServletAPI
- springmvc自定义拦截器
- springmvc之HelloWorld
- java多线程之线程的优先级
- java多线程之停止线程
- Ubuntu之Eclipse快捷方式
- 常考的java数据库笔试题
- Java编程思想学习笔记——注解
- java.io.FileNotFoundException: class path resource [bean.xml] cannot be opened because it does not e
- Zookeeper源码用ant进行编译为eclipse工程--转载
- Java中泛型的协变
- 12个Java的报表工具简介
- Java最简单的UDP实例
- Java面向对象编程-第6章学习笔记
- Myeclipse-解决Failed to load the JNI shared library一种方法
- Java 基础入门随笔(8) JavaSE版——静态static
- MyEclipse10.6 安装SVN插件方法及插件下载地址