Java中 static 和 volatile 的区别和应用场景

1.Static

1.1 关键字说明

static 声明这个字段是静态的(可能被多个实例共享),在主存区上该类的所有实例的该字段为同一个变量,即唯一性。

1.2 特点

static 只是声明变量在主存上的唯一性,不能保证工作区与主存区变量值的一致性;除非变量的值是不可变的,即再加上final的修饰符,否则static声明的变量,不是线程安全的。

2.volatile

2.1 关键字说明

volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。

2.2 特点

保证可见性,不保证原子性。
volatile, 声明这个字段易变(可能被多个线程使用),Java内存模型负责各个线程的工作区与主存区的该字段的值保持同步,即一致性。
volatile保证了每次工作内存操作前都去主存中取最新的值,解决了内存不可见性的问题,这是static没法做到的。

2.3 应用场景

1.计数器不能用,数据可能重复,导致脏读, 即i++操作,不能保证原子性。
2.状态标志可以用。
一个线程改boolean标志,另一个线程使用这个boolean变量。使用volatile可以保证马上能取到最新的值,每次去主存取。

2.4 缺陷,不保证原子性

比如两个线程对volatile变量进行i++操作1000次,实际跑出来的i值会<=2000,为什么?
一个线程操作完工作内存里的副本变量,会更新到主存中,在更新主存的过程中会进行加锁操作lock,此时如果另一个线程也想更新主存中的同一变量,就会自动失效本次操作,等上一线程更新完,再重新读取主存中的值。
因此,会有失效多次i++的情况,值就小于等于2000。

3.相同与不同

相同点:
1.他们都能够达到所有线程共享的目的。
2. 对于非原子性操作i++ 都是线程不安全的,可能出现数据重复。

不同点:
1.static 不保证可见性,未必能取到主存中最新的值。
2.volatile保证可见性,保证取到主存中最新的值。

4.原子性

即一个操作或者多个操作,要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。原子性就像数据库里面的事务一样,他们是一个团队,同生共死。

一个很经典的例子就是银行账户转账问题:比如从账户A向账户B转1000元,那么必然包括2个操作:从账户A减去1000元,往账户B加上1000元。
试想一下,如果这2个操作不具备原子性,会造成什么样的后果。假如从账户A减去1000元之后,操作突然中止。然后又从B取出了500元,取出500元之后,再执行 往账户B加上1000元 的操作。这样就会导致账户A虽然减去了1000元,但是账户B没有收到这个转过来的1000元。

所以这2个操作必须要具备原子性才能保证不出现一些意外的问题。同样地反映到并发编程中会出现什么结果呢?举一个简单的例子:

i = 0;       //1
j = i ;      //2
i++;         //3
i = j + 1;   //4

上面四个操作,有哪个几个是原子操作,那几个不是?如果不是很理解,可能会认为都是原子性操作,其实只有1才是原子操作,其余均不是。

1在Java中,对基本数据类型的变量和赋值操作都是原子性操作; 
2中包含了两个操作:读取i,将i值赋值给j 
3中包含了三个操作:读取i值、i + 1 、将+1结果赋值给i; 
4中同三一样

在单线程环境下我们可以认为整个步骤都是原子性操作,但是在多线程环境下则不同,Java只保证了基本数据类型的变量和赋值操作才是原子性的(注:在32位的JDK环境下,对64位数据的读取不是原子性操作*,如long、double)。

要想在多线程环境下保证原子性,则可以通过锁、synchronized来确保。volatile是无法保证复合操作的原子性。

参考文章链接

原子性参考文章:
https://blog.csdn.net/u013412772/article/details/80107643
https://blog.csdn.net/u013412772/article/details/80109727

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值