前言

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

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

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

举例说明

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

 package com.ccfdod.juc;

 public class TestVolatile {
public static void main(String[] args) {
ThreadDemo td = new ThreadDemo();
new Thread(td).start(); while(true) {
if (td.isFlag()) {
System.out.println("--------------");
break;
}
}
}
} class ThreadDemo implements Runnable {
private boolean flag = false; @Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = true;
System.out.println("flag = " + isFlag());
} public boolean isFlag() {
return flag;
} public void setFlag(boolean flag) {
this.flag = flag;
}
}

程序运行结果:

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不能保证变量的“原子性”

关于“原子性”的问题将在下一篇博客中讨论。

volatile关键字与内存可见性的更多相关文章

  1. volatile关键字与内存可见性&原子变量与CAS算法

    1 .volatile 关键字:当多个线程进行操作共享数据时, 可以保证内存中的数据可见 2 .原子变量:jdk1.5后java.util.concurrent.atomic 包下提供常用的原子变量 ...

  2. 详解volatile 关键字与内存可见性

    先来看一个例子: public class VolatileTest {            public static void main(String[] args) {           T ...

  3. 【JUC系列第一篇】-Volatile关键字及内存可见性

    作者:毕来生 微信:878799579 什么是JUC? JUC全称 java.util.concurrent 是在并发编程中很常用的实用工具类 2.Volatile关键字 1.如果一个变量被volat ...

  4. volatile关键字及内存可见性

    先看一段代码: package com.java.juc; public class TestVolatile { public static void main(String[] args) { T ...

  5. java 轻量级同步volatile关键字简介与可见性有序性与synchronized区别 多线程中篇(十二)

    概念 JMM规范解决了线程安全的问题,主要三个方面:原子性.可见性.有序性,借助于synchronized关键字体现,可以有效地保障线程安全(前提是你正确运用) 之前说过,这三个特性并不一定需要全部同 ...

  6. 【Java并发编程】6、volatile关键字解析&内存模型&并发编程中三概念

    volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java 5之后,volatile关键字才得以 ...

  7. volatile关键字解析&内存模型&并发编程中三概念

    原文链接: http://www.cnblogs.com/dolphin0520/p/3920373.html volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java5之前,它是一个 ...

  8. volotile关键字的内存可见性及重排序

    在理解volotile关键字的作用之前,先粗略解释下内存可见性与指令重排序. 1. 内存可见性 Java内存模型规定,对于多个线程共享的变量,存储在主内存当中,每个线程都有自己独立的工作内存,并且线程 ...

  9. Java并发机制(3)--volatile关键字与内存模型

    Java并发编程:volatile关键字解析及内存模型 个人整理自:博客园-海子-http://www.cnblogs.com/dolphin0520/p/3920373.html 1.线程内存模型: ...

随机推荐

  1. window7安装MongoDB详细步骤

    1.下载安装包 下载地址:https://www.mongodb.com/download-center/community 2.鼠标右击安装包,进行安装 3.选自定义安装 4.千万不要勾选 5.打开 ...

  2. 转载一篇pandas和,mysql

    http://pandas.pydata.org/pandas-docs/stable/comparison_with_sql.html#compare-with-sql-join http://bl ...

  3. 简明python教程三-----函数

    函数通过def关键字定义.def关键字后跟一个函数的表标识符名称,然后跟一对圆括号. 圆括号之中可以包括一些变量名,该行以冒号结尾.接下来是一块语句,它们是函数体. def sayHello(): p ...

  4. Eclipse ftp插件

    一个比较好的插件:esftp 下载地址http://sourceforge.net/projects/esftp/ 解压后放到plugins目录下重启即可. 配置estfp, 右击项目crm-> ...

  5. Changing an Elements innerHTML in TWebBrowser

    I'm unable to change the innerHTML of a javascript element, but i can change the id so i'm not sure ...

  6. WinIo简介

    WinIo简介 一日发现SendInput对某程序居然无效,无奈只好开始研究WinIo.上网查了很多资料,发现关于WinIo模拟鼠标键盘的资料很少,有的也只是支言片语讲的不是很详细,而且大部分都是关于 ...

  7. String与反序

    将String类型的字符串里的内容进行反序排列得到一个新的String类型字符串,下面提供两种方法实现: 法1.先将原String类型字符串转换为字符数组,通过字符数组来操作各个位上的单个字符,通过对 ...

  8. SOAPUI 压力测试的指标项说明

      soapUI Pro指标项说明:   Test Step Sets the startup delay for each thread (in milliseconds), setting to ...

  9. 错误:为 Web 项目“XXX”配置的 URL“http://localhost/”的网站同时存在于本地 IIS Web 服务器和 IIS Express Web 服务器上。您需要使用 IIS 管理器在 IIS 中更改此网站的绑定。

    解决方法: 用记事本打开MVC网站的项目文件(*.csproj),滚动条拉到最下,找到这两个节点: <UseIIS>True</UseIIS> <AutoAssignPo ...

  10. BZOJ 一句话题解

    菜鸡刷题记录 [题号:题解] 1008:简单排列组合 #include <bits/stdc++.h> using namespace std; #define ll long long ...