Java关键字-Synchronized

Synchronized用法

Synchronized关键字主要用在多线程并发时共享资源竞争的问题。当执行被synchronized关键字保护的代码片段时,将检查锁是否可用,若锁可用,则获取锁,执行代码,释放锁。 –《Java编程思想》

Synchronized的可以修饰类,方法,静态方法以及代码块。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Test {
private static final String TAG = "OutputUtil";
//修饰一个方法
synchronized void func1() {
//TODO
}
//修饰一个代码块
void func2() {
synchronized (this) {
//TODO
}
}
//修饰一个静态方法
synchronized static void func3() {
//TODO
}
//修饰一个类
void func4() {
synchronized (OutputUtil.class) {
//TODO
}
}
//修饰一个方法
synchronized void func5() {
//TODO
}
}

在修饰方法和代码块时,获得是对象锁;而修饰类和静态方法(属于类而不属于对象)时,获得是类锁。

1
2
Test test1 = new Test();
Test test2 = new Test();

接下来说明对象锁和类锁的区别:

顾名思义,对象锁的作用对象是针对单个对象的:在不同的线程执行test1.fun1()test2.fun1(),二者是互不干扰的。另外,同个对象的对象锁是互斥的,在不同线程执行test1.func1()test1.func5(),需等test1.func1()执行完毕释放test1的对象锁,test1.func5()拿到锁后才能执行。

而类锁的作用对象是整个类,在不同的线程执行test1.fun4()test2.fun4()是互斥的,必须先等test1.fun4()执行完毕,释放类锁,test2.fun4()才能执行。同理test1.fun3()test2.fun3()也是一样,因为使用synchronized修饰静态方法,拿到的也是类锁。

综上所述,可以得出结论:

  1. 同对象的对象锁是互斥的,不同对象的对象锁是非互斥的,对象锁和类锁也是非互斥的。
  2. 因为同步对运行效率有影响,因此尽量是用同步代码块越小越好,即尽量使用synchronized*(this)来同步一块代码,而不是直接修饰一整个方法。
  3. synchronized关键字是不能继承的。若子类覆盖了父类的synchronized方法,默认是没有同步的。
  4. 构造方法不能使用synchronized关键字,但是可以使用synchronized代码块来进行同步.
  5. 在定义接口方法时不能使用synchronized关键字。