volatile关键字
对比如下代码,如果不加volatile关键字则可能会导致即使执行了修改操作线程不能停止。因为main方法修改的是公共内存中的变量,线程内读取的是线程工作内存中的变量
class Service9 extends Thread {
// 不加volatile则线程不会停止,
// volatile 强制从公共内存中读取变量,如果不加volatile则优先从线程工作内存中读取变量,
// 可能导致公共内存和线程工作内变量不一致
volatile private boolean running = true;
public boolean isRunning() {
return running;
}
public void setRunning(boolean running) {
System.out.println("改变了running的值!");
this.running = running;
}
@Override
public void run() {
System.out.println("进入了run!");
while (running == true) {
}
System.out.println("离开了run!");
}
}
public class StudyThreads9volatile关键字强制从公共堆栈中取值 {
public static void main(String[] args) throws InterruptedException {
Service9 service9 = new Service9();
service9.start();
Thread.sleep(2000);
service9.setRunning(false);
}
}
对比synchronize和volatile
- 关键字volatile是synchronize的轻量级实现,性能比较好,volatile只能用于修饰变量,synchronize可以修饰方法及代码块
- 多线程访问volatile修饰的变量时候不会发生阻塞,synchronize可能会发生阻塞。
- volatile可以保证数据的可见性不能保证原子性,synchronize既可以保证数据的原子性又能间接保证数据的可见性。
- volatile解决的是多线程之间数据的可见性,synchronize解决的是多线程之间访问资源的同步性。
volatile非原子性
线程中对变量的加载操作是非原子性的,故volatile不能保证代码同步执行
class Service10 extends Thread {
volatile public static int count = 0;
// 给静态方法上锁 锁的是拥有改方法的类即对Service10上锁
// 不加锁则不能保证同步
synchronized private static void addCount() {
for (int i = 0; i < 100; i++) {
count++;
System.out.println(Thread.currentThread().getName() + ":" + count);
}
}
@Override
public void run() {
addCount();
}
}
public class StudyThreads10volatile关键字不保证原子性 {
public static void main(String[] args) {
Service10[] service10s = new Service10[1000];
for (int i = 0; i < service10s.length; i++) {
service10s[i] = new Service10();
}
for (int i = 0; i < 1000; i++) {
service10s[i].start();
}
}
}
synchronize: 保证同一时刻只有一个线程执行某个方法或代码块,它包含两个特征:互斥性和可见性。synchronize可以保证在进入synchronize之前所有修改后的结果。