多线程编程-volatile关键字(三)

2.3 volatile关键字

Volatile关键字的主要作用是使变量的多个线程间可见。还有一点就是禁止指令重排序。

 

使用volatile关键字增加了实例变量在多个线程之间的可见性,但是volatile不能保证原子性。

关键synchronized和volatile的比较:

1)volatile是线程同步的轻量级实现,所以volatile性能比synchronized要好,并且volatile只能修饰变量,而synchronized可以修饰方法,代码块。

2)多线程访问volatile不会发生阻塞,而synchronized会出现阻塞。

3)Volatile能保证数据的可见性,但不能保证原子性;而synchronized可以保证原子性,也可以间接保证可见性,因为他会将线程的私有内存和公共内存中的数据做同步。

4)Volatile解决的是变量在多个线程之间的可见性;synchronized解决的是多个线程之间资源访问的同步性。

2.3.1 volatile非原子特性

测试代码:

public class Thread1 extends Thread{
	public static int count =0;
	
	private static void addCount(){
		int index =0;
		while(index <100){
			count++;
			index++;
		}
		System.out.println("count = "+count);
	}
	@Override
	public void run(){
		addCount();
	}
}
public class RunDemo {

	public static void main(String[] args) {
		Thread1[] t1 = new Thread1[100];
		for(int i=0; i<100; i++){
			t1[i]= new Thread1();
		}
		for(int i=0; i<100; i++){
			t1[i].start();
		}		
	}
}

运行结果:

……

count = 9714

count = 9814

count = 9414

count = 9914

 

添加volatile关键字: public static int count=0;并不能解决这个问题,推荐的做法是使用synchronized关键字:synchronized privatestatic void addCount(){…},这种情况下volatile用不用都无所谓。

关键字volatile提示线程每次从共享内存读取变量,而不是从线程的工作内存读取,这保证了同步数据的可见性。但是这里的count++并不是一个原子操作,也就是非线程安全的。Count++可以分解为如下步骤:

1) 从内存取出count

2)计算count值(count  = count+1

3)将count值写入内存

在第二步时,如果其他线程也修改了count的值,就会出现脏读,解决这个问题的办法就是synchronized关键字。

下图展示了使用volatile时出现非线程安全的原因:


1) read和load阶段:从主存复制变量到线程工作内存;

2) use 和assign阶段;执行代码,改变共享变量值;

3) store 和write阶段:用线程工作内存数据刷新主存对应变量的值。

多线程环境下,use和assign是多次出现的,但这一操作不是原子性的,也即是在read和load后,如果主存count变量被修改了,线程工作内存中的值由于已经加载了,不会产生对应的变化,也就导致了工作内存和主存变量的不同步,出现了非线程安全。

Volatile修饰的变量,虚拟机只是保证从主存加载到线程工作内存的值是最新的,解决的是变量读时的可见性问题,无法保证操作的原子性,所以对于多线程访问同一个实例变量还要加锁同步。

2.3.2  使用原子类进行i++操作

除了使用synchronized实现同步外,还可以使用AtomicInteger原子类实现。

原子操作是不能分割的整体,没有其他线程能够中断或检查正在原子操作的变量。一个原子(atomic)类型就是一个原子操作可用的类型,他可以在没有锁的情况下做到线程安全。

public class Thread1 extends Thread{
	//volatile public static int count =0;
	private static AtomicInteger count = new AtomicInteger(0);
	//synchronized
	private static void addCount(){
		int index =0;
		while(index <100){
			//count++;
			count.incrementAndGet();
			index++;
		}
		System.out.println("count = "+count);
	}
	@Override
	public void run(){
		addCount();
	}
}
也可以得到期望结果。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕业设计,基于SpringBoot+Vue+MySQL开发的影城管理系统,源码+数据库+论文答辩+毕业论文+视频演示 随着现在网络的快速发展,网上管理系统也逐渐快速发展起来,网上管理模式很快融入到了许多生活之中,随之就产生了“小徐影城管理系统”,这样就让小徐影城管理系统更加方便简单。 对于本小徐影城管理系统的设计来说,系统开发主要是采用java语言技术,在整个系统的设计中应用MySQL数据库来完成数据存储,具体根据小徐影城管理系统的现状来进行开发的,具体根据现实的需求来实现小徐影城管理系统网络化的管理,各类信息有序地进行存储,进入小徐影城管理系统页面之后,方可开始操作主控界面,主要功能包括管理员:首页、个人中心、用户管理、电影类型管理、放映厅管理、电影信息管理、购票统计管理、系统管理、订单管理,用户前台;首页、电影信息、电影资讯、个人中心、后台管理、在线客服等功能。 本论文主要讲述了小徐影城管理系统开发背景,该系统它主要是对需求分析和功能需求做了介绍,并且对系统做了详细的测试和总结。具体从业务流程、数据库设计和系统结构等多方面的问题。望能利用先进的计算机技术和网络技术来改变目前的小徐影城管理系统状况,提高管理效率。 关键词:小徐影城管理系统;Spring Boot框架,MySQL数据库
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值