并发编程基础之volatile关键字的用法

一:概念

volatile关键字是一个轻量级的线程同步,它可以保证线程之间对于共享变量的同步,假设有两个线程a和b,

它们都可以访问一个成员变量,当a修改成员变量的值的时候,要保证b也能够取得成员变量最新的值,程序的

内存模型是这样的,程序运行时,成员变量的值被加载到内存中,如果线程a运行时,会把变量的值拷贝到cpu分配

给a的高速缓存区,就是内存的一个副本,线程b运行时,会把变量拷贝到cpu分配给b的高速缓存区,正常情况下,

a线程修改成员变量时,会将高速缓存中的值写入主存,然后b线程运行时读取主存中值到缓存,但是不是强制性的,

使用volatile关键字就是强制性。

1:将高速缓存强制写入主内存

2:会使b线程高速缓存标记失效

二:比较经典的一个示例

t1线程先启动,然后一直打印‘i love u’,这时t2线程启动,将flag变量的值修改为true,然后t1线程的执行终止,如果flag变量不加volatile修饰,

出现死循环的概率是存在的,但是比较低,如果加volatile,会强制t2线程修改主内存中flag的值,而且t1线程高速缓存标记会失效,可以保证

一定能够终止t1程序的执行

/**
 *
 */
package com.day2;

/**
 * @author Administrator
 *
 */
public class ListAdd1 {

	private boolean flag;

	public static void main(String[] args) {
		ListAdd1 list = new ListAdd1();

		//线程1
		Thread t1 = new Thread("t1"){
			public void run(){
				while(!list.flag){
					System.out.println("i love u");
				}
			}
		};

		//线程2
		Thread t2 = new Thread("t2"){
			public void run(){
				list.flag = true;
			}
		};

		t1.start();
		//保证t1线程先启动
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		t2.start();
	}

}
private volatile boolean flag;

  

但是volatile并不能保证操作的原子性,线程抢到cpu的时间片,修改高速缓存的值,写入主内存这几个过程不是原子的,

int i = 0;

i = i+1;

如果线程1在抢到cpu的时间片之后,还没有修改高速缓存的值,然后线程2也读取了主内存中缓存的值i = 0,然后执行加1,

写入高速缓存,线程1之前读取缓存中的值也是0,然后执行加1,写入主内存,这样就出现问题了,所以使用volatile不能

保证线程安全问题。

如下示例:

启动10个线程,count初始值为0,正常情况,10个线程个循环1000次,最后的count值应该为10000,但是不是,这个值

是随机的。

/**
 *
 */
package com.day2;

/**
 * @author Administrator
 *
 */
public class ListAdd2 {

	private volatile int count;

	public static void main(String[] args) {
		ListAdd2 list = new ListAdd2();

		System.out.println(list.count);

		for(int i=0;i<10;i++){
			new Thread("t"+i){
				public void run(){
					for(int j=0;j<1000;j++){
						list.count++;
					}
				}
			}.start();
		}

		System.out.println(list.count);
	}

}

  

如果想确保线程安全,那么必须使用synchronized锁

synchronized (list) {
							list.count++;
						}

 

因为10个线程访问的是同一个实例,所以使用对象锁就可以了。

时间: 2025-01-13 00:33:05

并发编程基础之volatile关键字的用法的相关文章

java并发编程--深入理解volatile关键字

??volatile是一个在java并发编程中耳熟能详的关键字.即使从来没有使用过,你也偶尔会在技术书籍或博客中见到.对volatile关键字的解释常常被一笔带过:被修饰的变量具有可见性,但不能保证原子性.但是到底如何保证可见性,可见性是什么--诸如此类的问题在碰到这种凝练的解释时会产生一种知其然不知其所以然的困惑.那么我将尽力在这一篇文章中将volatile关键字的意义彻底击穿. 可见性 ??可见性,顾名思义,可见程度.假如你在被窝里打开了手电筒,只有你自己知道手电筒打开了,那么可见性就非常差

python中并发编程基础1

并发编程基础概念 1.进程. 什么是进程? 正在运行的程序就是进程.程序只是代码. 什么是多道? 多道技术: 1.空间上的复用(内存).将内存分为几个部分,每个部分放入一个程序,这样同一时间在内存中就有了多道程序. 2.时间上的复用(CPU的分配).只有一个CPU,如果程序在运行过程中遇到了I/O阻塞或者运行时间足够长.操作系统会按照算法将CPU分配给其他程序使用,依次类推.直到第一个程序被重新分配到CPU会继续运行. 多道技术中的问题解决: 空间复用:程序之间的内存必须分割.这种分割需要在硬件

Java并发编程之验证volatile不能保证原子性

通过系列文章的学习,凯哥已经介绍了volatile的三大特性.1:保证可见性 2:不保证原子性 3:保证顺序.那么怎么来验证可见性呢?本文凯哥(凯哥Java:kaigejava)将通过代码演示来证明为什么说volatile不能够保证共享变量的原子性操作. 我们来举个现实生活中的例子: 中午去食堂打饭,假设你非常非常的饥饿,需要一荤两素再加一份米饭.如果食堂打饭的阿姨再给你打一个菜的时候,被其他人打断了,给其他人打饭,然后再回过头给你打饭.你选一荤两素再加一份米饭打完的过程被打断了四次耗时30分钟

4.java并发编程艺术-java并发编程基础

java从诞生开始就明智的选择了内置对多线程的支持,这使得java语言相比同一时期的其他语言具有明显的优势.线程作为操作系统调度的最小单元,多个线程能够同时执行,这将显著提升程序的性能,在多核环境中表现的更加明显.但是,过多的创建线程和对线程的不当管理也容易造成问题.本章将着重介绍java并发编程的基础知识,从启动一个线程到线程间不同的通信方式,最后通过简单的线程池示例以及应用(简单的Web服务器)来串联本章所介绍的内容. 1.线程简介 1.1 什么是线程 现代操作系统中在运行一个程序时,会为其

Scala入门到精通——第二十六节 Scala并发编程基础

作者:摇摆少年梦 视频地址:http://www.xuetuwuyou.com/course/12 本节主要内容 Scala并发编程简介 Scala Actor并发编程模型 react模型 Actor的几种状态 Actor深入使用解析 本节主要介绍的scala并发编程的基本思想,由于scala在2.10版本之后宣布使用akka作为其并发编程库,因此本节只进行基础性的内容介绍,后面将把重点放在akka框架的讲解上. 1. Scala并发编程简介 2003 年,Herb Sutter 在他的文章 "

[Java 并发编程实战] 对 volatile 变量进行实例验证(内含源码)

「 天行健,君子以自强不息.地势坤,君子以厚德载物.」---<易经> volatile 变量,在上一篇文章中已经有简单提及相关概念和用法,这一篇主要对 Volatile 变量的特性进行源码验证.验证它的涉及到的三个特性: 可见性 指令重排序 非原子性 volatile 之可见性验证 上一篇文章中,讲到 volatile 变量通常被当做状态标记使用.其中典型的应用是,检查标记状态,以确定是否退出循环.下面我们直接举个反例,源码如下: 1 public class Volatile { 2 3 b

Java并发编程里的volatile。Java内存模型核CPU内存架构的对应关系

CPU内存架构:https://www.jianshu.com/p/3d1eb589b48e Java内存模型:https://www.jianshu.com/p/27a9003c33f4 多线程下的缓存一致性问题:https://www.jianshu.com/p/97dc5242c3a6 java volatile关键字解惑:https://www.jianshu.com/p/195ae7c77afe Google-Java Memory Model:https://www.jianshu.

Java并发编程-基础概念全解

1.基础 1.1.什么是进程和线程 进程和线程都是操作系统所运行的程序运行的基本单元.进程可以说是是线程的集合. 进程:从系统资源讲,进程都有自己独立的地址空间,一个进程的崩溃不会影响另一个进程的执行. 线程:进程中的一个执行路径,一个进程中可以同时有多个线程在执行,当其中一个线程对公共资源做了修改,其他线程是可以看到的. 1.2.什么是并行和并发 并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时. 并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正

马士兵老师高并发编程基础入门

锁是指谁? Object o = new Object(); Synchronized(o); 我们一般认为Synchronized锁定的是这段代码块但事实上,Synchronized锁定的是锁这个对象.不仅如此Synchronized锁定的是heap内存中的这个对象而不是这个引用. 一个例子 /** * 锁定某对象o,如果o的属性发生改变,不影响锁的使用 * 但是如果o变成另外一个对象,则锁定的对象发生改变 * 应该避免将锁定对象的引用变成另外的对象 * @author mashibing *