java线程同步volatile与synchronized
2018-03-16 21:13
417 查看
转载自:http://blog.csdn.net/wdong_love_cl/article/details/52296078
前段时间面试时遇到这样一个问题:使用volatile修饰int型变量i,多个线程同时进行i++操作,这样可以实现线程安全吗?我感觉是不可以的,但是又说不出来为什么。下来后翻看了许多资料,终于了解了volatile的含义和用法了,一起来看看吧。
提到线程同步,我们经常会想到两个关键字:volatile和synchronized,那么这两者有什么区别呢?
volatile是变量修饰符,其修饰的变量具有可见性。在Java中为了加快程序的运行效率,对一些变量的操作通常是在寄存器或是cpu缓存上进行的,之后才会同步到内存中,而加了volatile修饰符的变量则是直接读写内存。可见性也就说一旦某个线程修改了该变量,其他线程读值时可以立即获取修改之后的值。
synchronized则作用于一段代码或方法,使用了该修饰符既可以保证可见性,也能够保证原子性。可见性表现在虽然其修饰的代码段或方法里面的读写操作可能在cpu缓存上进行的,不过在出代码段或方法前会把缓存中的数据同步到内存中。原子性表现在要么不执行,要么执行到底。
原子性看起来简单,其实不然,不信?看看下面几个例子:
x = 10; //语句1
y = x; //语句2
x++; //语句3
x = x + 1; //语句4
这四个语句哪些是原子操作?其实只有语句1是原子操作,怎么样,想不到吧?^^下面我来解释下
语句1就是1个动作,把10写入到内存。
语句2两个动作,先读取x的值,然后再写入内存。
语句3,4是一样的,有三个动作,读取x的值,计算,写入内存。
知道了这些,那么开头的问题就好理解了,比如有两个线程A和B对volatile修饰的i进行++操作,i的初始值是0,A线程执行i++时刚读取了i的值0,就切换到B线程了,B线程(从内存中)读取i的值也为0,然后就切换到A线程继续执行i++操作,完成后i就为1了,接着切换到B线程,因为之前已经读取过了,所以继续执行i++操作,最后的结果i就为1了。
从这里可以看出volatile虽然具有可见性但是并不能保证原子性。
volatile一般是用来作为状态标志的,看个我在java中如何结束线程 一文中举的例子:
[java] view plain copyclass MyThread extends Thread {
private volatile boolean isStop = false;
public void run() {
while (!isStop) {
System.out.println("do something");
}
}
public void setStop() {
isStop = true;
}
}
使用synchronized主要是用来保证线程安全的,看一个经典的单例模式(双重校验锁):
[java] view plain copyclass Singleton{
private volatile static Singleton instance = null;
private Singleton() {}
public static Singleton getInstance() {
if(instance==null) {
synchronized (Singleton.class) {
if(instance==null)
instance = new Singleton();
}
}
return instance;
}
}
synchronized的另一种用法是这样的(懒汉模式):
[java] view plain copyclass Singleton{
private volatile static Singleton instance = null;
private Singleton() {}
public static synchronized Singleton getInstance() {
if(instance==null)
instance = new Singleton();
return instance;
}
}
(哇塞volatile跟synchronized同台了耶!)
最后再来两篇扩展,写的都很棒!
1、volatile关键字解析,从内存模型,并发中的关键概念,讲到volatile的使用场景点击打开链接
2、多线程同步的五种方法点击打开链接
前段时间面试时遇到这样一个问题:使用volatile修饰int型变量i,多个线程同时进行i++操作,这样可以实现线程安全吗?我感觉是不可以的,但是又说不出来为什么。下来后翻看了许多资料,终于了解了volatile的含义和用法了,一起来看看吧。
提到线程同步,我们经常会想到两个关键字:volatile和synchronized,那么这两者有什么区别呢?
volatile是变量修饰符,其修饰的变量具有可见性。在Java中为了加快程序的运行效率,对一些变量的操作通常是在寄存器或是cpu缓存上进行的,之后才会同步到内存中,而加了volatile修饰符的变量则是直接读写内存。可见性也就说一旦某个线程修改了该变量,其他线程读值时可以立即获取修改之后的值。
synchronized则作用于一段代码或方法,使用了该修饰符既可以保证可见性,也能够保证原子性。可见性表现在虽然其修饰的代码段或方法里面的读写操作可能在cpu缓存上进行的,不过在出代码段或方法前会把缓存中的数据同步到内存中。原子性表现在要么不执行,要么执行到底。
原子性看起来简单,其实不然,不信?看看下面几个例子:
x = 10; //语句1
y = x; //语句2
x++; //语句3
x = x + 1; //语句4
这四个语句哪些是原子操作?其实只有语句1是原子操作,怎么样,想不到吧?^^下面我来解释下
语句1就是1个动作,把10写入到内存。
语句2两个动作,先读取x的值,然后再写入内存。
语句3,4是一样的,有三个动作,读取x的值,计算,写入内存。
知道了这些,那么开头的问题就好理解了,比如有两个线程A和B对volatile修饰的i进行++操作,i的初始值是0,A线程执行i++时刚读取了i的值0,就切换到B线程了,B线程(从内存中)读取i的值也为0,然后就切换到A线程继续执行i++操作,完成后i就为1了,接着切换到B线程,因为之前已经读取过了,所以继续执行i++操作,最后的结果i就为1了。
从这里可以看出volatile虽然具有可见性但是并不能保证原子性。
volatile一般是用来作为状态标志的,看个我在java中如何结束线程 一文中举的例子:
[java] view plain copyclass MyThread extends Thread {
private volatile boolean isStop = false;
public void run() {
while (!isStop) {
System.out.println("do something");
}
}
public void setStop() {
isStop = true;
}
}
使用synchronized主要是用来保证线程安全的,看一个经典的单例模式(双重校验锁):
[java] view plain copyclass Singleton{
private volatile static Singleton instance = null;
private Singleton() {}
public static Singleton getInstance() {
if(instance==null) {
synchronized (Singleton.class) {
if(instance==null)
instance = new Singleton();
}
}
return instance;
}
}
synchronized的另一种用法是这样的(懒汉模式):
[java] view plain copyclass Singleton{
private volatile static Singleton instance = null;
private Singleton() {}
public static synchronized Singleton getInstance() {
if(instance==null)
instance = new Singleton();
return instance;
}
}
(哇塞volatile跟synchronized同台了耶!)
最后再来两篇扩展,写的都很棒!
1、volatile关键字解析,从内存模型,并发中的关键概念,讲到volatile的使用场景点击打开链接
2、多线程同步的五种方法点击打开链接
相关文章推荐
- java线程同步volatile与synchronized(二)
- Java线程同步synchronized和volatile
- java线程同步volatile与synchronized
- java线程同步volatile与synchronized
- java线程同步volatile与synchronized(三)
- Java线程同步问题synchronized
- Java线程同步:synchronized锁住的是代码还是对象
- Java线程同步:synchronized锁住的是代码还是对象
- Java线程同步:synchronized锁住的是代码还是对象
- Java线程(二):线程同步synchronized和volatile
- 使用synchronized进行Java线程同步
- java线程等待、设置优先级、同步、挂起、恢复(Join、setPriority、synchronized、wait、notify……)
- java线程同步——synchronized (wait、notify)
- Java线程的同步 - synchronized
- Java 线程 — synchronized、volatile、锁
- java线程安全篇之synchronized对象锁的同步和异步(三)
- 线程的同步机制2-synchronized-Java
- Java基础-多线程-③线程同步之synchronized
- 【Java多线程】多线程的线程安全及同步(synchronized)用法
- java 线程之synchronized,volatile,原子类,Lock锁相关