synchronized、volatile、Atomic区别和用法

可见性:指的是在一个线程中修改变量的值以后,在其他线程中能够看到这个值。
synchronized关键字除了有互斥的作用外,还有可见性的作用。synchronized保证了synchronized块中变量的可见性,而volatile则是保证了所修饰的变量的可见。因为volatile只是在保证了同一个变量在多线程中的可见性,所以它更多是用于修饰作为开关状态的变量,即Boolean类型的变量。
int i1; public int geti1() {return i1;}
public void seti1(int i1) {this.i1=i1;}
volatile i2; public int geti2() {return i2;}
public void seti2(int i2) {this.i2=i2;}
int i3; public synchronized int geti3() {return i3;}
public synchronized void seti3(int i3) {this.i3=i3;}
代码中对于geti1的调用获取的是当前线程中的副本(这里说的当前线程副本和主内存在上一篇文章   JVM 多线程的内存模型中主要简绍了,不懂的可以回头看一下),这个值不一定是最新的值。对于geti2,因为i2被修饰为volatile,因此对于JVM来说这个变量不会有线程的本地副本,只会放在主存中,所以得到的值一定是最新的。而对于geti3,因为有synchronized关键字修饰,保证了线程的本地副本与主存的同步,所以也会得到最新的值,这是针对读层面的。
对于seti1,当前线程在调用了seti1后会得到最新的i1值,而在另外的线程获取不一定可以立刻看到最新的值。对于seti2,则可以立刻在其他线程看到新的值,因为volatile保证了只有一份主存中的数据。对于seti3,调用后必须在synchronized修饰的方法或代码块中读取i3的值才可以看到最新值,因为synchronized不仅会把当前线程修改的变量的本地副本同步给主存,还会从主存读取数据更新本地副本。
volatile变量虽然解决了并发时的可见性问题,但是不能控制并发操作,例如:
volatile count = 0;
Hashtable<String, String> h = new Hashtable<String, String>();
public void addContent(String key, String value) {
if(count < 100) {
h.put(key, value);
count ++;
}
}
在jdk5中增加了java.util.concurrent.atomic包,这个包中是一些以Atomic开头的类,这些类主要提供一些相关的原子操作。以上的多线程并发对计数器对volatile变量加1操作可以修改为这样:
private AtomicInteger counter = new AtomicInteger();
// 加 1
private int increase() {
return counter.incrementAndGet();
}
// 减 1
private int decrease() {
return counter.decrementAndGet();
}
Atomic修饰的类进行的操作相对于synchronized修饰的代码块会有很大性能上的提升,建议在计数器相关的多线程并发中用Atomic开头的相关类进行操作。
总结:volatile多用于修饰类似开关类型的变量、Atomic多用于类似计数器相关的变量、其它多线程并发操作用synchronized关键字修饰。







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值