关于java中的synchronization与volatile关键字
关于java中的synchronization与volatile关键字
java中的同步是用关键字synchronized和volatile实现
在java中,我们不能使用syncchronized去修饰变量,用synchronized去修饰变量是非法的。我们可以用volatile代替synchronized去修饰变量,volatile会通知JVM从主内存读取变量而不是从cache中读取。
如果一个变量并没有在多线程中共享,那么就不要使用volatile
使用volatile修饰的变量,这个变量的改变对每个线程都是可见的,一旦改变,其它线程会立刻知道。
5.
volatile使用示例
public class Singleton {
private static volatile Singleton instance;
private Singleton() {
// do something to prevent from reflection
}
public static Singleton getInstance() {
if (instance == null) {
synchronized(Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
在以上的示例中使用了懒加载的单例。如果我们没有使用volatile修饰instance,那么正在创建instance的thread即使创建了instance也不能通知到其它线程。例如:当threadA刚刚创建完instance,cpu切换了线程,那么其它的线程并不知道instance已经创建了,还会认为instance是null;
为什么呢?因为等待的线程并没有进行任何锁定,直到拥有锁的线程从同步块出来,在这个瞬间,线程间的内存将不会同步,并且instance的值不会在主内存中更新。 使用Java中的volatile关键字,Java会自己处理,让所有的线程都可以看到这些更新。
来张内存示意图
volatile并不能保证变量值是多线程同步的
public class Test {
public volatile int inc = 0;
public void increase() {
inc++;
}
public static void main(String[] args) {
final Test test = new Test();
for(int i=0;i<10;i++){
new Thread(){
public void run() {
for(int j=0;j<1000;j++)
test.increase();
};
}.start();
}
while(Thread.activeCount()>1) //保证前面的线程都执行完
Thread.yield();
System.out.println(test.inc);
}
}
大家想一下这段程序的输出结果是多少?也许有些朋友认为是10000。但是事实上运行它会发现每次运行结果都不一致,都是一个小于10000的数字。
可能有的朋友就会有疑问,不对啊,上面是对变量inc进行自增操作,由于volatile保证了可见性,那么在每个线程中对inc自增完之后,在其他线程中都能看到修改后的值啊,所以有10个线程分别进行了1000次操作,那么最终inc的值应该是1000*10=10000。
这里面就有一个误区了,volatile关键字能保证可见性没有错,但是上面的程序错在没能保证原子性。可见性只能保证每次读取的是最新的值,但是volatile没办法保证对变量的操作的原子性。
使用示例
下面列举几个Java中使用volatile的几个场景。
1.状态标记量
volatile boolean flag = false;
while(!flag){
doSomething();
}
public void setFlag() {
flag = true;
}
volatile boolean inited = false;
//线程1:
context = loadContext();
inited = true;
//线程2:
while(!inited ){
sleep()
}
doSomethingwithconfig(context);
2.double check
class 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;
}
}
关于java中的synchronization与volatile关键字相关教程