synchronized的四种作用域以及不能被继承解析
synchronized
是java
中用于同步
的关键字,其典型的作用域如下所示.
1 对象锁
@Slf4j
public class SynchronizedExample1 {
private final int loopNum = 20;
// 修饰一个代码块
private void test1(int j) {
synchronized (this) {
for (int i = 0; i < loopNum; i++) {
log.info("test1 {} - {}", j, i);
}
}
}
// 修饰一个方法
private synchronized void test2(int num) {
for (int i = 0; i < loopNum; i++) {
log.info("test2 {} - {}", num, i);
}
}
public static void main(String[] args) {
SynchronizedExample1 example1 = new SynchronizedExample1();
SynchronizedExample1 example2 = new SynchronizedExample1();
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(() -> {
example1.test2(1);
});
executorService.execute(() -> {
example2.test2(2);
});
executorService.shutdown();
}
}
1.1 代码块修饰(对象)
此时,synchronized
用于保证test1
函数中的被synchronized
大括号包裹的代码同步执行.
synchronized
作用的对象为SynchronizedExample1
的对象实例,例如main
函数中的example1
以及example2
.
Tips:
1.example1
若在多个线程中被调用,其输出顺序将保证同步,按照1,2,3...19,20
的顺序执行.
2.若example1
与example2
均在多个线程中执行,则test1...
之间保持同步输出,test2...
之间保持同步输出,但是test1...
与test2...
之间输出不保证顺序.
1.2 非静态函数修饰
synchronized
添加于test2
函数声明中,其作用类似于1.1
中的代码块修饰,区别点仅仅在于
其同步代码块扩充至整个函数
(test2
).
2. 类锁
@Slf4j
public class SynchronizedExample2 {
private static final int loopNum = 20;
// 修饰一个类
private static void test1(int j) {
synchronized (SynchronizedExample2.class) {
for (int i = 0; i < loopNum; i++) {
log.info("test1 {} - {}", j, i);
}
}
}
// 修饰一个静态方法
private static synchronized void test2(int j) {
for (int i = 0; i < loopNum; i++) {
log.info("test2 {} - {}", j, i);
}
}
public static void main(String[] args) {
SynchronizedExample2 example1 = new SynchronizedExample2();
SynchronizedExample2 example2 = new SynchronizedExample2();
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(() -> {
example1.test1(1);
});
executorService.execute(() -> {
example2.test1(2);
});
}
}
2.1 代码块修饰(类)
与1.1
中区别在于,synchronized
函数修饰的是SynchronizedExample2
类.
SynchronizedExample2
对象,诸如example1
或者example2
在任意多的线程中调用test1
函数,其输出顺序均会被保证(1,2,3,4...19,20
).
2.2 静态函数修饰
功能与2.1
类似,均是对对象加锁,确保多个类对象调用函数时保持顺序.
Tips:
示例中,因为类上加锁的原因,test1
与test2
对象保持顺序执行,不会出现test1...
与test2...
交叉出现的现象.
3 synchronized
不能被继承
需要注意,若synchronized
修饰于函数中,如1.2
以及2.2
,若有类继承于SynchronizedExample1
或者SynchronizedExample1
,子类对象调用test2
不同步.
原因:synchronized
非函数签名,因此无法被继承,所以无法保证子类调用同步.
PS:
如果您觉得我的文章对您有帮助,可以扫码领取下红包,谢谢!