synchronized 关键字详解 - Xiasm/Java-Android-Learn GitHub Wiki
注:参考了Jekton关于synchronized的博客,感谢作者。 原文链接
synchronized关键字一共有两种用法,分别为作用在代码块和作用在方法上。如下:
synchronized作用在代码块上:
synchronized (A.class) {
}
synchronized作用在方法上:
public synchronized void test() {
}
synchronized 加锁时,使用的是对象的内置锁(intrinsic lock),任何 Java 对象都拥有这个锁,所以任何 Java 对象都可以用来给 synchronized 执行同步。synchronized 语句使用的对象由我们显式指定,synchronized 方法则用的是方法所属的那个对象的内置锁。
我们知道,静态方法不属于任何对象,那静态的 synchronized 方法又用的是哪个锁呢?
回想一下,刚刚我提到,任何 Java 对象都可以用来给 synchronized 执行同步。虽然静态方法不关联对象,但是,他却属于所在的那个类实例。下面我们通过例子说明一下:
class Foo {
public static synchronized void foo() {}
}
这里的 foo() 属于 class Foo。我们又知道,Java 里,class Foo 对应着这样一个类实例 Foo.class。Foo.class 也是一个对象,所以他能够被用来加锁。静态的同步方法,就是使用对应的类实例来进行加锁的。
同样,对应静态的代码块,我们也可以这样做:
static {
synchronized (Foo.class) {
// your stuff...
}
}
说完了 synchronized 的一些基本用法,下面讲讲和它相关的 wait() 和 notify(), notifyAll()。
在某些情况下,我们可能要先获取锁,然后检查某些条件,如果条件不满足,则放弃锁,稍后再重试。
// some thread
synchronized (mLock) {
while (!condition) {
wait();
}
}
// another thread
synchronized (mLock) {
condition = true;
notify();
// or notifyAll();
}
这个时候, wait() 和 notify(), notifyAll() 就派上用场了。执行 wait() 后,会释放锁,然后进入休眠。稍后,其他某个线程修改条件,并重新唤醒前面那个线程。先前调用 wait() 的线程被唤醒后,会自动重新获得锁。也就是说,wait() 调用返回后,该线程仍然持有锁。
注:某些面试官喜欢让面试者回答 wait() 和 sleep() 的区别。sleep() 是 class Thread 的一个方法,它所做的就是直接去睡觉(不释放锁),两者的区别是非常明显的。