volatile浅析

概述

volatile是java中的一个关键字,主要什么作用呢?

  1. 把变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享的,因此不会对该变量上的操作与其他内存操作仪器重排序。
  2. volatile变量不会被缓存在寄存器或者对其他处理器不可见的地方,因此在读取volatile类型的变量总是会返回最新的写入数据

volatile工作机制

java内存模型(图片出处:http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html):

blog mark

volatile 修饰的变量read的时候直接从内存中加载,而且store的时候即为write,即内存可见性。单纯的读->写操作,可以理解为写入volatile变量相当于退出同步代码块,而读取volatile变量就相当于进入同步代码块。
下面主要来看一段代码:



import java.util.*;

/**
 * Created by sanyinchen on 15/12/4.
 */
public class volatileMain {
    static  volatile int i = 0;

    private static void increase() {
        i++;
    }

    public static void main(String[] arges) {

        int max=10000;
        Thread[] threadList = new Thread[max];
        for (int number = 0; number < max; number++) {
            Thread t=new Thread() {
                @Override
                public void run() {
                    super.run();
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    increase();
                }
            };
            threadList[number]=t;
        }

        for (int number = 0; number < max; number++) {
            threadList[number].start();
        }
       for (int number = 0; number < max; number++) {
            if(threadList[number].isAlive()){
                try {
                    threadList[number].join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println("activeCount : " + Thread.activeCount());
        ThreadGroup group=Thread.currentThread().getThreadGroup();
        Thread[] sidList=new Thread[group.activeCount()];
        group.enumerate(sidList);
        for(int j=0;j<sidList.length;j++){
            System.out.println(j+" thread name -- "+sidList[j].getName());
        }

        System.out.println("i : " + i);
    }
    }

输出结果:

activeCount : 2  
0 thread name -- main  
1 thread name -- Monitor Ctrl-Break  
i : 9810  

先来解释一下这段代码:
首先new出10000个线程,遍历循环start(),runable中执行increase()方法,将成员变量i++.
遍历循环线程池,将没有执行完的线程调用join()方法,这里的join()的意思是阻塞当前的线程,也就是main()线程,等待其join的线程执行完毕。这里主要是保证所开的线程全部执行完成。最后输出结果和当前存存活的线程,来检验程序的运行结果是否有说服力。

那么最后的结果为何是<1000的呢?volatile是一个轻量级的同步机制,write和read确实是原子操作,那么它的问题出在i++,i=i+1需要经过:
1. 读取i
2. 对i进行操作
3. 将i写入主内存
即时1与3是原子的,但是任然不能保证对i的操作是原子的,这就是导致问题的所在。

volatile的应用

  1. volatile最广泛的应用时作为一个标记
    我们会经常这么写:

    boolean asleep;
    while(!asleep){
    // do somthing
    }
    

    这里若是单线程不会有什么问题,问题是如果是多线程,asleep在经过每个线程的内存空间的时候就可能会导致并发导致最终写入主内存的asleep是true。那么就将导致死循环.
    正确的写法是:

    volatile boolean asleep;
    while(!asleep){
    // do somthing
    }
    
  2. 另外再提一下就是在单例模式初始化延迟加载double check中的适用,这里大家有兴趣的话可以去查阅一些相关资料


转载请注明出处:
http://blog.csdn.net/sanyinchen/article/details/50901580

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值