volatile关键字与内存可见性

volatile关键字与内存可见性
前言

首先,我们使用多线程的目的在于提高程序的效率,但是如果使用不当,不仅不能提高效率,反而会使程序的性能更低,因为多线程涉及到线程之间的调度、CPU上下文的切换以及包括线程的创建、销毁和同步等等,开销比单线程大,因此需谨慎使用多线程。

在jdk1.5以后,提供了一个强大的java.util.concurrent包,这个包中提供了大量的应用于线程的工具类。

下面开始介绍volatile关键字和内存可见性,虽然volatile是在jdk1.5之前就有的,但还是想放在这里讲一下。

举例说明

首先,我们先看一段小程序。

复制代码
1 package com.ccfdod.juc;
2
3 public class TestVolatile {
4 public static void main(String[] args) {
5 ThreadDemo td = new ThreadDemo();
6 new Thread(td).start();
7
8 while(true) {
9 if (td.isFlag()) {
10 System.out.println(“————–”);
11 break;
12 }
13 }
14 }
15 }
16
17 class ThreadDemo implements Runnable {
18 private boolean flag = false;
19
20 @Override
21 public void run() {
22 try {
23 Thread.sleep(200);
24 } catch (InterruptedException e) {
25 e.printStackTrace();
26 }
27 flag = true;
28 System.out.println(“flag = ” + isFlag());
29 }
30
31 public boolean isFlag() {
32 return flag;
33 }
34
35 public void setFlag(boolean flag) {
36 this.flag = flag;
37 }
38 }
复制代码
程序运行结果:

flag = true
并且程序不会停止。

按理来说,应该会在td线程修改flag值后,主线程会打印出“————–”,但是为什么没有出现预期效果呢?下面来分析这段程序,涉及到内存可见性问题。

内存可见性问题

当程序运行时,JVM会为每一个执行任务的线程分配一个独立的缓存空间,用于提高效率。

不难理解,程序开始执行时,由于线程td修改flag操作之前,sleep了200ms,td线程和main线程获取到的flag都为false,但为什么td线程将flag改为true后,main线程没有打印出“————–”呢?原因在于:while(true)是执行效率很高,使得main线程没有时间再次从主存中获取flag的值,因此程序在td线程将flag修改为true后,没有停止运行的原因。其实在while(true)后面稍微延迟一点(比如说,打印一句话),都会使main线程将主存中的flag=true读取。

产生这种情况的原因就在于,两个线程在操作共享数据时,对共享数据的操作是彼此不可见的。

那么为了不让这种问题出现,怎么解决呢?

一、使用synchronized同步锁

复制代码
while(true) {
synchronized (td) {
if (td.isFlag()) {
System.out.println(“————–”);
break;
}
}
}
复制代码
使用synchronized同步锁能保证数据的及时更新。但是效率太低。

二、使用volatile关键字

当多个线程进行操作共享数据时,可以保证内存中的数据可见。底层原理:内存栅栏。使用volatile关键字修饰时,可理解为对数据的操作都在主存中进行。

private volatile boolean flag = false;
相较于synchronized是一种较为轻量级的同步策略。

注意:

volatile不具备“互斥性”
volatile不能保证变量的“原子性”

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值