1. 多线程安全问题
- 当多线程并发访问临界资源时,如果破坏原子操作,可能会造成数据不一致
- 临界资源:共享资源(同一对象),一次仅允许一个线程使用,才可保证其正确性
- 原子操作:不可分割的多步操作,被视作一个整体,其顺序和步骤不可打乱和缺省
1.1 同步与异步
以调用方角度来讲,如果需要等待结果返回,才能继续运行就是同步;不需要等待结果返回,就能继续运行就是异步
2. synchronized
- Java 中的锁是对象
- synchronized 声明方法时,放在 public 之前和之后没有区别
2.1 特点
- 原子性
- 可见性
- 有序性
3. 对象锁
- synchronized 方法是将当前对象作为锁,而 synchronized 代码块是将任意对象作为锁
3.1 同步方法
方法声明里的 synchronized 并不是锁方法,而是锁当前类的对象
public synchronized void method() {
}
synchronized (this) {
}
2.2 静态同步方法
类锁
3. synchronized 锁重入
当一个线程得到一个对象锁后,再次请求此对象锁时可以再次得到该对象锁
锁重入也支持在父子类中继承
/**
* synchronized 特性:
* 1. 可重入
* 2. 不可中断
*
* 可重入锁 -> 不需要重新竞争锁
* 1. 同一线程的外层函数获得锁之后,内层函数可以直接再次获取该锁
* 2. 好处:避免死锁、提升封装性
* 3. 粒度
* 情况一:同一个方法是可重入的
* 情况二:可重入锁不要求是同一个方法
* 情况三:可重入锁不要求是同一个类中的
*
* synchronized 优先使用轻量级锁加锁,如果加锁失败了再使用重量级锁
*
* CAS(Compare-and-Swap),即比较并替换
*
* 自旋优化 -> 自旋重试
*
*/
static final Object obj = new Object();
public static void method1() {
synchronized (obj) {
method2();
}
}
public static void method2() {
synchronized (obj) {
// do something
}
}
5. println()
同一个对象的两个同步代码块也是同步的
public class PrintStream extends FilterOutputStream implements Appendable, Closeable {
public void println(String x) {
synchronized (this) {
print(x);
newLine();
}
}
public void println(Object x) {
String s = String.valueOf(x);
synchronized (this) {
print(s);
newLine();
}
}
网友评论