- 目录
- 前言
- 场景
- 知其所以然
- 注意
- 小结
前言
关于synchronized这个关键字,笔者这里不想像书中一样,用大量的示例来做演示,希望通过一个例子,作归纳和总结。
场景
已知存在一个类Sample(该类有两个实例对象sampleAlpha,sampleBeta),如下图所示。
public class Sample {
private Object lock = new Object();
public synchronized void one() {...}
public synchronized void two() {...}
public void three() {...}
public void four() {
synchronized (this) {
...
}
}
public void five() {
synchronized (lock) {
...
}
}
public static synchronized void six() {
...
}
public void seven() {
synchronized (Sample.class) {
...
}
}
}
下面我们来分不同场景讨论下同步的问题:
同一个实例对象:
1.线程A执行实例对象
sampleAlpha中的one方法,同时线程B执行实例对象sampleAlpha中的two方法,同步执行。
2.线程A执行实例对象sampleAlpha中的one方法,同时线程B执行实例对象sampleAlpha中的three方法,异步执行。
3.线程A执行实例对象sampleAlpha中的one方法,同时线程B执行实例对象sampleAlpha中的four方法,同步执行。
4.线程A执行实例对象sampleAlpha中的one方法,同时线程B执行实例对象sampleAlpha中的five方法,异步执行。
5.线程A执行实例对象sampleAlpha中的one方法,同时线程B执行实例对象sampleAlpha中的six方法,异步执行。
6.线程A执行实例对象sampleAlpha中的one方法,同时线程B执行实例对象sampleAlpha中的seven方法,异步执行。
7.线程A执行实例对象sampleAlpha中的six方法,同时线程B执行实例对象sampleAlpha中的seven方法,同步执行。
不同的实例对象:
8.线程A执行实例对象
sampleAlpha中的one方法,同时线程B执行实例对象sampleBeta中的two方法,异步执行。
9.线程A执行实例对象sampleAlpha中的six方法,同时线程B执行实例对象sampleBeta中的seven方法,同步执行。
……其他类似情况,不一一列举
知其所以然
为什么会出现上述的几种不同情况呢?下面来具体讨论:
第1种:
线程A执行方法one的时候已经持有了该方法所属对象的锁,当线程B执行方法two的时候,会和线程A竞争该对象的锁,进入等待状态,当线程A释放该对象的锁后,线程B继续持有该锁,继续执行。
第2种:线程A执行方法one的时候已经持有了该方法所属对象的锁,当线程B执行方法three的时候,并没有同步锁,不需要竞争,直接执行完毕。
第3种:synchronized(this)获取的也是该对象的锁,参考第1种方式。
第4种:线程A执行方法one的时候已经持有了该方法所属对象的锁,当线程B执行方法five的时候,线程B持有的是另外一个对象锁lock,不会和线程A产生竞争,故异步执行。
第5种:线程A执行方法one的时候已经持有了该方法所属对象的锁,当线程B执行方法six的时候,此时线程B持有的不是该对象的锁,而是Class类锁,和线程A竞争的不是同一个,故而异步执行。
第6种:同第5种解释。
第7种:同步执行的原因在于静态同步synchronized方法和synchronized(class)代码块,都是获取当前Class类的锁,对该类产生的所有对象实例起作用。
第8种:由于线程A和线程B持有的都不是同一个对象的锁,故而异步执行,不会产生同步。
第9种:由于线程A和线程B虽然操作的是不同的对象实例,但是他们持有的都是同一个Class类的锁,故而产生竞争,同步执行。
注意
1.由于常量池的原因,大多数情况下
synchronized代码块都不要使用String作为锁对象,最好使用new Object()实例化一个对象。
2.关键字synchronized不具有继承性,但是可以在子类中标记该关键字,在父子继承关系中,实现可重入锁。
3.当线程执行出现异常时,其所持有的锁会自动释放。
小结
从上面的几个例子,我们明白了,synchronized修饰方法和synchronized(this)获取的都是当前实例对象的锁,synchronized静态方法和synchronize(class)获取的是Class类的锁,这是两种不同的锁,而要想多线程产生同步,则多个线程竞争的必须是同一个锁。
牢记这一点,做一个心中有锁的人。
本文通过一个具体的示例,深入探讨了Java中synchronized关键字的作用机制。详细分析了不同场景下同一实例及不同实例间的锁竞争行为,帮助读者理解synchronized锁的工作原理。
981

被折叠的 条评论
为什么被折叠?



