java中volatile关键字---学习笔记
2016-06-30 14:31
351 查看
volatile关键字的作用
在java内存模型中,线程之间共享堆内存(对应主内存),但又各自拥有自己的本地内存——栈内存,线程的栈内存中缓存有共享变量的副本,但如果是被volatile修饰的变量,线程每次都直接从堆内存中读取最新值,并在操作完成时将新值写入堆内存。
但需要注意的一点是:volatile关键字只能保证主存中的变量值是最新的,并不能保证操作的原子性,因此它不能代替synchronized。像简单的i++也不是原子操作,它包括了read(i),inc(i),write(i)的过程,可能:当一个线程刚从主存中读取出i的最新值还未进行下一步操作时,另一个线程正往主存中写入新值,此时就会出现线程不安全的情况。
什么是线程安全?
通俗的解释就是:有多个线程在同时运行一段代码,如果每次运行的结果和单线程运行的结果一样,而且其他的变量值也和预期的一样,这样叫做线程安全。例子:一个线程安全的计数器类的同一个实例对象在被多个线程使用的情况下也不会出现计算失误。
volatile拥有可见性但是不具有原子性的验证
这里通过创建1000个线程对同一个计数器Counter进行++操作来验证volatile的线程安全性。为了排除main thread最后读取count值时,尚有线程没有结束的情况,这里引入 Java concurrent包里面的一个同步辅助类CountDownLatch,通过countDown()方法和await()方法来保证main thread最后读取到的count值是主存中最新的。
CountDownLatch latch = new CountDownLatch(1000); //用给定的计数次数1000进行初始化。
latch.countDown(); //此操作是原子操作,即同时只允许有一个线程去减这个计数器里面的值。
latch.await();//在计数器latch里面的值变为0之前一直处于阻塞状态。
运行结果:
测试结果说明:java中的volatile关键字只可保证读取可见性但并不是线程安全的,在实际使用过程中,我们要具体情况具体分析。
在java内存模型中,线程之间共享堆内存(对应主内存),但又各自拥有自己的本地内存——栈内存,线程的栈内存中缓存有共享变量的副本,但如果是被volatile修饰的变量,线程每次都直接从堆内存中读取最新值,并在操作完成时将新值写入堆内存。
但需要注意的一点是:volatile关键字只能保证主存中的变量值是最新的,并不能保证操作的原子性,因此它不能代替synchronized。像简单的i++也不是原子操作,它包括了read(i),inc(i),write(i)的过程,可能:当一个线程刚从主存中读取出i的最新值还未进行下一步操作时,另一个线程正往主存中写入新值,此时就会出现线程不安全的情况。
什么是线程安全?
通俗的解释就是:有多个线程在同时运行一段代码,如果每次运行的结果和单线程运行的结果一样,而且其他的变量值也和预期的一样,这样叫做线程安全。例子:一个线程安全的计数器类的同一个实例对象在被多个线程使用的情况下也不会出现计算失误。
volatile拥有可见性但是不具有原子性的验证
这里通过创建1000个线程对同一个计数器Counter进行++操作来验证volatile的线程安全性。为了排除main thread最后读取count值时,尚有线程没有结束的情况,这里引入 Java concurrent包里面的一个同步辅助类CountDownLatch,通过countDown()方法和await()方法来保证main thread最后读取到的count值是主存中最新的。
CountDownLatch latch = new CountDownLatch(1000); //用给定的计数次数1000进行初始化。
latch.countDown(); //此操作是原子操作,即同时只允许有一个线程去减这个计数器里面的值。
latch.await();//在计数器latch里面的值变为0之前一直处于阻塞状态。
import java.util.concurrent.CountDownLatch; public class Counter { public volatile static int count = 0; CountDownLatch latch = new CountDownLatch(1000); public static void inc() { count++; } //1000 threads start simultaneously for i ++ calculations, to see the actual results ; public void test() throws InterruptedException { for (int i = 0; i < 1000; i++) { new Thread(new Runnable() { @Override public void run() { Counter.inc(); } }).start(); latch.countDown(); //Ensure that all threads have been completed ; System.out.println("Come here " + (i + 1) + " times"); } latch.await(); //Until 1000 threads complete before reading the counter value inside ; System.out.println(Thread.currentThread().getName() + " thread : " + Counter.count); } //Here the value of each run are likely to differ , possibly 1000 ; public static void main(String[] args) { try { new Counter().test(); } catch (InterruptedException e) { e.printStackTrace(); } } }
运行结果:
测试结果说明:java中的volatile关键字只可保证读取可见性但并不是线程安全的,在实际使用过程中,我们要具体情况具体分析。
相关文章推荐
- manven项目Java Resource红叉报错的处理
- java的动态代理机制详解
- java知识巩固
- 利用Java针对MySql封装的jdbc框架类 JdbcUtils 完整实现(包含增删改查、JavaBean反射原理,附源码)
- Array数组对象常用操作总结(一)
- Elasticsearch java API (18)Aggregations 聚合 Bucket
- Quartz Spring 整合入门
- Android Eclipse使用.aar文件攻略
- Gsonformat——json快速生成javaBean
- 单链表Singly Linked List之JAVA实现
- java多线程之CountDownLatch
- MyEclipse 常用快捷键
- java多线程之Callable和Future
- java多线程之ExecutorService
- 关于Maven的错误集合和解决方法
- java中Class.forName的含义
- SpringMVC的几种返回方式
- javax.servlet.jsp.JspException cannot be resolved to a type
- 升级struts2漏洞的方法
- Java理论知识--类和对象