Java支持多线程,在解决并发问题的时候引入了synchronized和volatile,下面就分析两种同步的区别:
synchronized
synchronized修饰的代码块或者方法,在线程访问的时候一次只允许一个线程使用,相当于给程序加锁,在当前线程没有结束的时候,其他线程无法进入从而进入等待状态,synchronized是线程安全的
volatile
volatile修饰变量,volatile是各个线程可见的,对volatile修饰的变量的更新会立即同步主内存中,volatile是线程不安全的
public
class
Counter {
public
volatile
static
int
count =
0
;
public
static
void
inc() {
//这里延迟1毫秒,使得结果明显
try
{
Thread.sleep(
1
);
}
catch
(InterruptedException e) {
}
count++;
}
public
static
void
main(String[] args) {
//同时启动1000个线程,去进行i++计算,看看实际结果
for
(
int
i =
0
; i <
1000
; i++) {
new
Thread(
new
Runnable() {
@Override
public
void
run() {
Counter.inc();
}
}).start();
}
//这里每次运行的值都有可能不同,可能为1000
System.out.println(
"运行结果:Counter.count="
+ Counter.count);
}
}
运行结果:Counter.count=992
运行结果还是没有我们期望的1000,下面我们分析一下原因
每个线程运行时都有一个线程栈,线程栈保存了线程运行时变量的信息,当某一个线程访问一个对象的时候,会通过对象的引用找到变量在堆内存中的信息,然后load到本地内存中,建立一个变量副本,之后就是通过操作副本,在修改后线程退出之前,在把更新之后的值写到对象在堆内存中的值
read and load 从主存复制变量到当前工作内存
use and assign 执行代码,改变共享变量值
store and write 用工作内存数据刷新主存相关内容
其中 use and assign 可以多次出现
但是这一些操作并不是原子性,也就是在read load 之后,如果内存count变量发生修改之后,
线程工作内存中的值由于已经加载,所以不会产生对应的变化,所以计算出来的结果会和预期不一样
对于volatile修饰的变量,jvm虚拟机只是保证从主内存加载到线程工作内存的值是最新的
假如线程1,线程2在进行到read 、load操作中,发现主内存中count的值都是5,那么会加载这个最新的值
在线程1堆count进行修改之后,会write到主内存中,主内存中的count变量就会变为6
线程2由于已经read、load操作,在进行运算之后,也会更新主内存count的变量值为5,导致两个线程及时用volatile关键字修改之后,还是会存在并发的情况
参考http://www.cnblogs.com/aigongsi/archive/2012/04/01/2429166.html