并发编程的3个特点分别是:原子性、可见性、有序性
作用:轻量级并发编程锁,解决内存可见性问题、防止指令重排序(有序性);
public class volatileTest {
private static volatile boolean flag = false;
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
// 如果 flag 变量为 true 就终止执行
while (!flag) {
}
System.out.println("终止执行");
}
});
t1.start();
// 1s 之后将 flag 变量的值修改为 true
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("设置 flag 变量的值为 true!");
flag = true;
}
});
t2.start();
}
}
// 设置flag变量的值为true!
// 终止执行
如果没有设置volatile,程序不会结束执行
public class Singleton {
private Singleton() {}
// 使用 volatile 禁止指令重排序
private static volatile Singleton instance = null;
public static Singleton getInstance() {
if (instance == null) { // ①
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton(); // ②
}
}
}
return instance;
}
}
/* 懒汉式需要使用volantile来防止指令重排序
②处执行时,指令是有可能触发重排序的,这里实际执行分为3步
1. 创建内存空间
2. 在内存空间中初始化对象Singleton
3. 将内存地址赋值给 instance对象(执行此步骤就不等于null了)
*/
volatile的第2点作用一般常见的场景也是单例模式下的场景
作用:
专业:如果一个对象对多个线程可见,则对该对象变量的所有读取和写入都是通过同步方法完成的
通俗:能够保证在同一个时刻最多只有一个线程执行该段代码,以达到保证并发安全的效果
锁:
对象锁:
类锁:
原理:
public class Main{
int sum=0;
public synchronized void add(){
++sum;
}
public void add2(){
synchronized (Main.class) {
++sum;
}
}
}
简单的阐述一下synchronized机制。通过javap -c Main.class
命令查看字节码
// synchronized 加在方法上
public synchronized void add();
Code:
0: aload_0
1: dup
2: getfield #2 // Field sum:I
5: iconst_1
6: iadd
7: putfield #2 // Field sum:I
10: return
// synchronized加在方法内
public void add2();
Code:
0: ldc #3 // class com/monk/volatiletest/Main
2: dup
3: astore_1
4: monitorenter
5: aload_0
6: dup
7: getfield #2 // Field sum:I
10: iconst_1
11: iadd
12: putfield #2 // Field sum:I
15: aload_1
16: monitorexit
17: goto 25
20: astore_2
21: aload_1
22: monitorexit
23: aload_2
24: athrow
25: return
Exception table:
from to target type
5 17 20 any
20 23 20 any
}
通过上图自己买来看,同步方法并没有通过指令monitorenter
和monitorexit
来实现,而是通过常量池下的ACC_SYNCHRONIZED
标识符实现方法的同步;
对同步代码块来说,则是通过monitorenter
和monitorexit
指令控制Monitor
的权限,也就是通过这俩指令控制锁的权限