java的synchronized关键字

性质:可重入,不可中断
两种用法:对象锁(方法锁,同步代码块锁),类锁(静态方法,class对象)
多线程访问同步方法的7种情况
加解锁原理(计数器加减),可重入原理,可见性原理(写回主内存再通信)
书籍:Java并发编程实战

对象锁

同步代码块

1
2
3
synchronized (this){
n++;
}
1
2
3
4
5
6
7
8
9
10
11
Object lock1 = new Object();
Object lock2 = new Object();
//两个lock锁定的不同代码块可以并行执行
...

synchronized (lock1){
n++;
}
synchronized (lock1){
m++;
}

方法锁

1
2
3
public synchronized void addition(){
n++;
}

类锁

静态方法

1
2
3
public synchronized static void addition(){
n++;
}

class对象

1
2
3
synchronized (*.class){
n++;
}

7种常见情况

  1. 两个线程同时访问一个对象的同步方法 – 串行
  2. 两个线程访问两个对象的同步方法 – 并行
  3. 两个线程访问synchronized得静态方法 – 串行
  4. 同时访问同步和非同步方法 – (一个线程访问同步方法,一个访问非同步,不影响)并行
  5. 访问同一个对象的不同的普通同步方法(非static方法) – (同一个实例默认使用this)串行
  6. 同时访问静态synchronized和非静态synchronized方法 – 并行
  7. 方法抛异常后会释放锁 – Lock类型的锁不会释放

性质

可重入

同一线程的外层函数获得锁之后,内层函数可直接再次获取该锁(同一把锁)
内层函数可以是1.同一个方法2.不同方法3.不同类(子父类)
好处:避免死锁,提升封装性
粒度:线程而非调用(pthread的粒度是调用)

不可中断

Lock接口

1
2
3
4
5
6
Lock lock = new ReentrantLock();
public void method(){
lock.lock();
n++;
lock.unlock();
}

反编译

1
2
javac test.java //编译
javap -verbose test.class //反编译查看字节码,-verbose把信息打印出来

缺陷

  1. 效率低:不可中断,不能设置超时,锁释放情况少
  2. 不够灵活:加锁释放时机单一,每个锁仅有单一条件(对比之下,读写锁更加灵活)
  3. 无法知道是否成功获取到锁

注意点

锁对象不能为空
作用域不宜过大
避免死锁

Lock与synchronized尽量避免使用,可以使用java.util.concurrent包下的各种工具类
synchronized代码更简洁
同步访问的各种情况

锁的优化
锁的升级降级,偏斜锁,轻量级锁,重量级锁