【Java基础】多线程之volatile
2017-06-24 22:02
176 查看
首先明确和synchronized的区别:
1:volatile是变量修饰符,而 synchronized作用于一段代码或者是方法。2:多线程访问volatile不会发生阻塞,而synchronized会出现阻塞。
3:volatile能保证数据的可见性,但是保证不了原子性,而synchronized可以保证原子性,也可以间接地保证可见性,因为他会将私有内存和公共内存中的数据做同步。
4:关键字volatile是解决变量多个线程之间的可见性,关键字synchronized是解决多个线程之间访问资源的同步性。
没有使用关键字volatile
package cn.itcast.java.base.isvolatile; public class MyThread extends Thread { public static int count = 0; public static void inc() { //这里延迟1毫秒,使得结果明显 try { Thread.sleep(1); } catch (InterruptedException e) { } count++; } public static void main(String[] args) { //同时启动1000个线程,去进行i++计算,看看实际结果 for (int i = 0; i < 1000; i++) { new Thread(new Runnable() { @Override public void run() { MyThread.inc(); } }).start(); } //这里每次运行的值都有可能不同,可能为1000 System.out.println("运行结果:Counter.count=" + MyThread.count); } }
我们来看一下运行结果:
运行结果:Counter.count=979
首先我来说一下count++这个语句,该语句进行的操作是将值从内存的地址读取到寄存器中,对寄存器的值进行加1操作,然后再把新值写回到内存中,由于count++并不是原子的,所以俩个线程或者是多个线程同时进行++就会产生数据混乱,也就是各个线程的count是不一致的。
当多个线程对count变量进行拷贝的时候,由于在各个线程中count的值是不一样的,比如一个线程A将count改变成了80,存放在主内存中是80,而另一个线程B的此时正在运行的count值却是在修改80之前拿的,也就是79,于是它又加了一个1,变成了80。线程B改变了各自的值,但是这个改变是还没有来得及传递给主内存区域或者其他线程时候就已经发生的了。
使用关键字volatile
package cn.itcast.java.base.isvolatile; public class MyThread extends Thread { public volatile static int count = 0; public static void inc() { //这里延迟1毫秒,使得结果明显 try { Thread.sleep(1); } catch (InterruptedException e) { } count++; } public static void main(String[] args) { //同时启动1000个线程,去进行i++计算,看看实际结果 for (int i = 0; i < 1000; i++) { new Thread(new Runnable() { @Override public void run() { MyThread.inc(); } }).start(); } //这里每次运行的值都有可能不同,可能为1000 System.out.println("运行结果:Counter.count=" + MyThread.count); } }
运行结果:
运行结果:Counter.count=791
为什么使用了,却还不是1000呢?因为它保证可见性,却不能保证原子性。
关键字volatile是可以知道变量的值被更改了,并且可以获的最新的值的使用,也就是用多线程读取共享变量时候可以获得最新值使用。
为了保证可见性和原子性,我们可以一起用关键字volatile和synchronized。
线程工作的内存
在多线程环境中,use和assign是多次出现的,但是这个并不能保证原子性,也就是在read和load之后,如果主内存变量count发生修改之后,线程工作内存中的值由于已经加载,不会产生对应的变化,也就是私有内存和公共内存中的变量不能同步,所以计算出来的结果和预期不一样,也就出现了非线程安全的问题。
对于用volatile修饰的变量,JVM虚拟机只是保证从主内存加载到线程工作内存的值是最新的,例如线程1和线程2都进行了load和read操作,发现主内存中count的值都是5,那么他们都会加载这个最新的值,也就是volatile解决的是可见性问题。
相关文章推荐
- java多线程基础总结【一】volatile关键字与原子性问题
- Java多线程基础篇(02)-多线程的实现
- java 多线程基础--多线程及并发
- JAVA基础【10.1】《Java核心技术1》多线程1
- 黑马程序员_java基础-多线程
- java多线程之内存可见性-synchronized、volatile
- ***JAVA多线程和并发基础面试问答
- java多线程基础(四)
- Java的多线程机制系列:(一)总述及基础概念
- Java多线程基础知识
- java基础 多线程 简单总结
- JAVA多线程和并发基础面试问答(转载)
- Java多线程基础
- 黑马程序员——Java基础--多线程(一)
- 【Java基础】并发 - 多线程
- 【JAVA多线程】volatile关键字在JAVA多线程编程中的作用
- 黑马程序员——Java基础多线程
- Java多线程基础
- 黑马程序员--java基础--多线程
- Java多线程编程基础之线程对象