Synchronized特性
- 原子性
- 可见性
JMM关于synchronized的两条规定:
- 线程解锁前,必须把共享变量的最新值刷新到主内存中.
- 线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量时需要从主内存中重新读取最新的值(注意:加锁与解锁需要是同一把锁).
Synchronized实现可见性
- 线程执行互斥代码的过程:
1.获得互斥锁
2.清空工作内存
3.从主内存拷贝变量的最新副本到工作内存
4.执行代码
5.将更改后的共享变量的值刷新到主内存.
6.释放互斥锁.
代码案例,实现非线程安全
public class SynchronizedDemo {
//共享变量
private boolean ready = false;
private int result = 0;
private int number = 1;
//写操作 加上 synchronized 可保证线程原子性
public void write(){
ready = true; //1.1
number = 2; //1.2
}
//读操作 加上 synchronized 可保证线程原子性
public void read(){
if(ready){ //2.1
result = number*3; //2.2
}
System.out.println("result的值为:" + result);
}
//内部线程类
private class ReadWriteThread extends Thread {
//根据构造方法中传入的flag参数,确定线程执行读操作还是写操作
private boolean flag;
public ReadWriteThread(boolean flag){
this.flag = flag;
}
@Override
public void run() {
if(flag){
//构造方法中传入true,执行写操作
write();
}else{
//构造方法中传入false,执行读操作
read();
}
}
}
public static void main(String[] args) {
SynchronizedDemo synDemo = new SynchronizedDemo();
//启动线程执行写操作
synDemo .new ReadWriteThread(true).start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//启动线程执行读操作
synDemo.new ReadWriteThread(false).start();
}
}
Volatile特性
- 非原子性
- 可见性
Volatile使用场景
要在多线程中安全的使用volatile变量,必须同时满足:
1.对变量的写入操作不依赖于其当前值
即改变后的volatile变量的值不能与它之前的值有关系.
2.该变量没有包含在具有其他变量的不变式中.
即不能存在通过volatile变量进行逻辑判断.