volatile和synchronized的区别
volatile 关键字,使一个变量在多个线程间可见,简单说就是volat变量修改后,所有线程都能立刻实时的看到这个最新值,主要解决内存可见性问题。
synchronized关键字:解决执行控制问题
public class T1 {
/**
* volatile 关键字,使一个变量在多个线程间可见
* A B线程都用到一个变量,java默认是A线程中保留一份copy,这样如果B线程修改了该变量,则A线程
* 未必知道
* 使用volatile关键字,会让所有线程都会读到变量的修改值
* <p>
* 在下面的代码中,running是存在于堆内存的t对象中
* 当线程t1开始运行的时候,会把running值从内存中读到t1线程的工作区,在运行过程中直接使用这个
* copy,并不会每次都去
* 读取堆内存,这样,当主线程修改running的值之后,t1线程感知不到,所以不会停止运行
* <p>
* 使用volatile,将会强制所有线程都去堆内存(主内存)中读取running的值
* <p>
* volatile并不能保证多个线程共同修改running变量时所带来的不一致问题,也就是说volatile不能
* 替代synchronized
*/
/*volatile*/ boolean running = true;//对比一下有无volatile的情况下,整个程序运行结果的区别
void m() {
System.out.println("m start");
while (running) {
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("m end!");
}
public static void main(String[] args) {
T1 t = new T1();
new Thread(t::m, "t1").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
t.running = false;
}
}
public class T2 {
/**
* volatile并不能保证多个线程共同修改running变量时所带来的不一致问题,也就是说volatile不能
* 替代synchronized
* 运行下面的程序,并分析结果(证明volatile不是原子操作案例)
*/
volatile int count = 0;
void m() {
for (int i = 0; i < 10000; i++)
count++;
}
public static void main(String[] args) {
T2 t = new T2();
List<Thread> threads = new ArrayList<Thread>();
for (int i = 0; i < 10; i++) {
threads.add(new Thread(t::m, "thread-" + i));
}
threads.forEach((o) -> o.start());
threads.forEach((o) -> {
try {
o.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println(t.count);
}
public class T3 {
/**
* 对比上一个程序,可以用synchronized解决,synchronized可以保证可见性和原子性,volatile只
* 能保证可见性
*/
/*volatile*/ int count = 0;
synchronized void m() {
for (int i = 0; i < 10000; i++)
count++;
}
public static void main(String[] args) {
T3 t = new T3();
List<Thread> threads = new ArrayList();
for (int i = 0; i < 10; i++) {
threads.add(new Thread(t::m, "thread-" + i));
}
threads.forEach((o) -> o.start());
threads.forEach((o) -> {
try {
o.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println(t.count);
}
}
1.volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取;。2.synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
3.volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的。
4.volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性。
5.volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
6.volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化。