0%

Java 并发 - Synchronized 几种使用方式

1.概括

Synchronized 可以有几种修饰方法,总体使用如下图所示:

image.png

2.具体使用

2.1 修饰代码块

指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁。

  • 注意:它只作用于同一个对象,如果调用两个对象上的同步代码块,就不会进行同步。和 synchronized 方法一样,synchronized(this)代码块也是锁定当前对象的。synchronized 关键字加到 static 静态方法和 synchronized(class)代码块上都是是给 Class 类上锁。这里再提一下:synchronized关键字加到非 static 静态方法上是给对象实例上锁。另外需要注意的是:尽量不要使用 synchronized(String a) 因为JVM中,字符串常量池具有缓冲功能!
1
2
3
4
5
public void func() {
synchronized (this) {
// ...
}
}

2.2 修饰实例方法

  • 作用于当前对象实例加锁,进入同步代码前要获得当前对象实例的锁。
  • 注意:它和同步代码块一样,作用于同一个对象。
1
2
3
public synchronized void fun(){
// ...
}

2.3 同步一个类

  • 注意:作用于整个类,也就是说两个线程调用同一个类的不同对象上的这种同步语句,也会进行同步。
1
2
3
4
5
public void func(){
synchronized (SynchronizedExample.class){
// ...
}
}

2.4 修饰静态方法

作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁 。

  • 注意:作用于整个类。也就是给当前类加锁,会作用于类的所有对象实例,因为静态成员不属于任何一个实例对象,是类成员(static 表明这是该类的一个静态资源,不管new了多少个对象,只有一份,所以对该类的所有对象都加了锁)。所以如果一个线程A调用一个实例对象的非静态 synchronized 方法,而线程B需要调用这个实例对象所属类的静态 synchronized 方法,是允许的,不会发生互斥现象,因为访问静态 synchronized 方法占用的锁是当前类的锁,而访问非静态 synchronized 方法占用的锁是当前实例对象锁。
1
2
3
public synchronzied static void func (){
// ...
}

Synchronized 修饰静态方法相当于如下:

1
2
3
4
5
6
class X {
// 修饰静态方法
synchronized(X.class) static void bar(){
// 临界区
}
}