今天来说说volatile和synchronized的区别,我们都知道volatile和synchronized是java高并发中常见的关键字。
volatile
volatile具备可见性,这里仅仅指的是对其他线程的可见性,也就是允许其他线程访问的共享变量。
在这里volatile比较适合一个线程写多个线程读的场景,因为volatile不是不具备原子性,所以使用起来不适用于多个线程写的场景。
synchronized
java中的每一个对象都可以进行作为锁,有三种方式的锁
1.同步方法锁(实例对象),这里锁定的是当前的实例对象。
public class demo_001 {
private int count=0;
public void m()
{
synchronized(this) // 锁定对象
{
count--;
System.out.println(Thread.currentThread().getName()+"-----count="+count);
}
}
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName());
demo_001 d = new demo_001();
d.m();
}
}
2.静态同步方法,这里锁的是类的class对象。因为静态的方法和变量等都是存放于java虚拟机的方法区里面跟对象所存放的位置不一样(对象存放在java堆里面)。
public class demo_003 {
private static int count = 10;
public static synchronized void m() { // 等同于 synchronized (c_004.T.class) {
count--;
System.out.println(Thread.currentThread().getName() + " count = " + count);
}
public static void main(String[] args) {
demo_003 d = new demo_003();
d.m();
}
}
3.同步方法块,锁定的是部分的代码,有些时候方法体比较大的时候如果我们整个锁住就会造成性能上的丢失。这里有一点需要特别注意的就是说是锁定代码块,但其实这里锁定的还是当前的实例对象,也就是说锁定方法是属于锁定对象中的一部分。
public class demo_002 {
private int count = 0;
public synchronized void m() //锁定方法
{
count--;
System.out.println(Thread.currentThread().getName()+"-----count="+count);
}
public static void main(String[] args) {
demo_002 d = new demo_002();
d.m();
}
}
下面来讲讲volatile和synchronized的区别,从上面我们可以知道volatile具备了可见性不具备原子性,而synchronized具备原子性也具备可见性。
public class demo_004 {
private volatile static int count = 10;
private static int count1 = 10;
static synchronized void run(){
count1--;
System.out.println(Thread.currentThread().getName()+"----count1="+count1);
}
public static void main(String[] args)
{
for(int i=0;i<10;i++)
{
new Thread(()->{
run();
/*
while(count>0) //volatile不具备原子性,在while中多个线程进行判断的时候会造成数据不一致的情形
{
count--;
System.out.println(Thread.currentThread().getName()+"---count="+count);
}*/
}).start();
}
}
}
由上面的两张图我们可以看出volatile是不具备原子性的而synchronized是具备原子性的,所以使用的时候需要多加注意才行。
另外这里还有值得一提的就是volatile除了可见性以外是禁止指令重排序的,物理机模型为了提高效率在运行的时候不会保证对代码进行先后顺序的执行,这里volatile保证了它不会被重排序。