Java多线程-Volatile变量学习记录

与synchronized关键字区别:

2020-3-25 这两个比较某种程度上并不是一个层面,volatile不具有原子性,只是读写前后加入屏障进行的可见性保障。

synchronized是JVM对程序的加锁机制,会使执行线程阻塞;volatile变量则不会,所以说是相对于synchronized而言更轻量的同步机制。

作用
1.volatile修饰的变量可以保证更新操作对其它线程可见(普通变量是做不到这一点的,普通变量只能借助于主内存来让其他线程获取,但是volatile修饰的变量则不用,执行引擎使用它时都会去刷新获取);
2.当被它修饰后,编译器与运行时都会注意到这个变量是共享的,所以不会将该变量上的操作和其他内存操作一起重排序。
禁止指令重排序是第二个语义

注意:

/**
 * 类描述:volatile保证变量更新可见性,但是不保证是原子性,所以使用的时候仍然需要注意线程安全。
 * @author: Wanggd
 *	时间:2017年5月29日
 */
public class VolatileTest {
	public static volatile int race = 0;
	
	public static void increase(){
		//++计算并不是原子的。要想保证线程安全,依然需要借助synchronized或者lock。
		race ++;
	}
	
	private static final int THREADS_COUNT = 20;
	
	public static void main(String[] args) {
		Thread[] threads = new Thread[THREADS_COUNT];
		for(int i=0;i<threads.length;i++){
			threads[i] = new Thread(new Runnable() {
				
				public void run() {
					for(int i=0;i<10000;i++){
						increase();
					}
				}
			});
			threads[i].start();
		}
		
		while(Thread.activeCount() > 1){
			Thread.yield();
		}
		
		System.out.println(race);
		//期望结果为200000
		//实际结果往往小于200000;  193582 问题出在++操作。
	}

}

另一个volatile的案例就是单例模式:
http://blog.csdn.net/kevin_king1992/article/details/72801015

2020-3-25 最近又学习了一下这个知识点,并且分享下面一个简单的示例,大家可以运行下看看,很多框架中常见到类似的案例。

import java.util.Random;

/**
 * 应用volatile可见性的例子,常用于判断性的场景。
 * 下面是一个模拟容器启动失败后再度调用的例子。
 */
public class VolatileDemo {

    public static void main(String[] args) {
        SpringContainer springContainer = new SpringContainer();
        new Thread(new SpringRunTask(springContainer)).start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("--启动监控Spring容器是否初始化完成,否则继续初始化--");
        while (!springContainer.successInit) {
            System.out.println("-- 再重新初始化一次,否则将记录错误 --");
            springContainer.init();
        }

        System.out.println("--Spring容器初始化完成,初始化完成关闭当前线程--");
    }

    static class SpringRunTask implements Runnable{
        private SpringContainer springContainer;

        SpringRunTask (SpringContainer springContainer) {
            this.springContainer = springContainer;
        }

        @Override
        public void run() {
            springContainer.init();
        }
    }

    static class SpringContainer {

        public volatile boolean successInit = false;

        public void init() {
            System.out.println("Spring Application Context Init....");
            try {
                Thread.sleep(300);

                /**
                 * 设置1/3的概率失败
                 */
                int r = new Random().nextInt(3);
                if (r == 1) {
                    throw new RuntimeException("初始化异常....");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            successInit = true;
            System.out.println("Completed...");
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值