synchronized
1. 锁的是对象
2. 非静态 锁的是this 静态 锁的是 XX.class
3. 锁定方法 与 非锁定方法可以同时执行
4. 锁升级
- synchronized锁 可重入
- 执行时间短(加锁代理),
- 线程数少, 用自旋
- 执行时间长,线程数多,用系统锁
1加锁的方式:
public class T {
private Object o = new Object(); // 锁
private int count = 10;
public void m() {
synchronized(o) { //任何线程要执行下面的代码,必须先拿到o的锁
count--;
System.out.println(Thread.currentThread().getName() + " count = " + count);
}
}
}
2.加锁的方式:
public class T {
private int count = 10;
public void m() {
synchronized(this) { //任何线程要执行下面的代码,必须先拿到this的锁
count--;
System.out.println(Thread.currentThread().getName() + " count = " + count);
}
}
}
3.加锁的方式:
public class T {
private int count = 10;
public synchronized void m() { //等同于在方法的代码执行时要synchronized(this)
count--;
System.out.println(Thread.currentThread().getName() + " count = " + count);
}
}
4.静态加锁的方式:
public class T {
private static int count = 10;
public synchronized static void m() { //这里等同于synchronized(FineCoarseLock.class)
count--;
System.out.println(Thread.currentThread().getName() + " count = " + count);
}
public static void mm() {
synchronized(T.class) { //考虑一下这里写synchronized(this)是否可以?
count --;
}
}
}
Demo:
public class T implements Runnable {
private int count = 10;
public synchronized void run() {
count--;
System.out.println(Thread.currentThread().getName() + " count = " + count);
}
public static void main(String[] args) {
for(int i=0; i<5; i++) {
T t = new T();
new Thread(t, "THREAD" + i).start();
}
}
}
volatile
1. 保证线程可见性
- MESI
- 缓存一致性协议
2. 禁止指令重排序
- DCL单例
- Double Check Lock
- Mgr06.java
- loadfence 原语指令
- storefence 原语指令
单例 设计模式
饿汉式
/**
* 饿汉式
* 类加载到内存后,就实例化一个单例,JVM保证线程安全
* 简单实用,推荐使用!
* 唯一缺点:不管用到与否,类装载时就完成实例化
*/
// 饿汉式方式一
public class Hungry01 {
private static final Hungry01 INSTANCE = new Hungry01();
private Hungry01() {};
public static Hungry01 getInstance() {
return INSTANCE;
}
public void m() {
System.out.println("m");
}
public static void main(String[] args) {
Hungry01 m1 = Hungry01.getInstance();
Hungry01 m2 = Hungry01.getInstance();
System.out.println(m1 == m2);
}
}
// 饿汉式方二
public class Hungry02 {
private static final Hungry02 INSTANCE;
static {
INSTANCE = new Hungry02();
}
private Hungry02() {};
public static Hungry02 getInstance() {
return INSTANCE;
}
public void m() {
System.out.println("m");
}
public static void main(String[] args) {
Hungry02 m1 = Hungry02.getInstance();
Hungry02 m2 = Hungry02.getInstance();
System.out.println(m1 == m2);
}
}
懒汉式
/**
* 懒汉式 lazy loading
* 虽然达到了按需初始化的目的,但却带来线程不安全的问题
* 可以通过synchronized解决,但也带来效率下降
*/
// 懒汉式
public class lazy01 {
private static volatile lazy01 INSTANCE; //JIT
private lazy01() {}
public static lazy01 getInstance() {
if (INSTANCE == null) {
//双重检查
synchronized (lazy01.class) {
if(INSTANCE == null) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new lazy01();
}
}
}
return INSTANCE;
}
public void m() {
System.out.println("m");
}
public static void main(String[] args) {
for(int i=0; i<100; i++) {
new Thread(()->{
System.out.println(lazy01.getInstance().hashCode());
}).start();
}
}
}
解决同样的问题的更高效的方法,使用AtomXXX类
AtomXXX 类本身方法都是原子性的,但不能保证多个方法连续调用是原子性的
- CAS (无锁优化 自旋)
- Compare And Set/Swap
- cas(V,Expected,NewValue) // Expected 期望值 如果一样则执行
- if V == E
V = New
otherwise try again or fail - CPU 原语支持
- if V == E
- ABA 问题
加 version 版本号
A 1.0
B 2.0
C 3.0
cas(version)
基础类型 无所谓
引用类型 注意 和女朋友复合,中间经历了别的女人
Unsafe
直接操作内存
allocateMemory putXX freeMemory pageSize
直接生成类实例
allocateInstance
直接操作类或实例变量
objectFieldOffset
getInt
getObject
CAS相关操作
weakCompareAndSetObject Int Long