synchronized 关键字详解 - Xiasm/Java-Android-Learn GitHub Wiki

注:参考了Jekton关于synchronized的博客,感谢作者。 原文链接

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()。

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 的一个方法,它所做的就是直接去睡觉(不释放锁),两者的区别是非常明显的。

⚠️ **GitHub.com Fallback** ⚠️