Java 多线程

synchronized 方法

synchronized 关键字只能用于修饰方法和代码块,而且不能用于修饰构造方法。

参考 Java Language Specification Chapter 17. Threads and Locks

A synchronized method automatically performs a lock action when it is invoked; its body is not executed until the lock action has successfully completed. If the method is an instance method, it locks the monitor associated with the instance for which it was invoked (that is, the object that will be known as this during execution of the body of the method). If the method is static, it locks the monitor associated with the Class object that represents the class in which the method is defined. If execution of the method’s body is ever completed, either normally or abruptly, an unlock action is automatically performed on that same monitor.

也就是说

1
2
3
4
5
6
7
8
// 写法 1
public class DemoOne {
private int a = 0;

synchronized public void methodOne() {
a++;
}
}
1
2
3
4
5
6
7
8
9
10
// 写法2
public class DemoOne {
private int a = 0;

public void methodOne() {
synchronized (this) {
a++;
}
}
}

写法 1 等同于写法 2。

1
2
3
4
5
6
7
8
// 写法 3
public class DemoOne {
private static int a = 0;

synchronized public static void methodOne() {
a++;
}
}
1
2
3
4
5
6
7
8
9
10
// 写法 4
public class DemoOne {
private static int a = 0;

public static void methodOne() {
synchronized (DemoOne.class) {
a++;
}
}
}

写法 3 等同于 写法 4。

住:以上“等同”仅仅指代码执行效果相同,但是两种写法编译之后生成的字节码不一定相同。

任何线程进入同步方法或者同步代码块之前,需要先获得 Monitor 对象。那同步方法和同步代码块什么时候会释放 Monitor 对象呢?

有以下几种情况:

  • 当前线程的同步方法执行结束、无论是正常结束还是异常结束。
  • 在当前线程执行同步方法或者同步代码块的时候调用了同步监视器对象的 wait() 方法。

以下几种情况不会释放同步监视器对象:

  • 线程执行同步方法或者同步代码块的时候,程序调用 Thread.sleep() 方法或者 Thread.yield() 方法暂停当前线程的执行,当前线程不会释放同步监视器。
  • 线程执行同步方法或者同步代码块的时候,其他线程调用了该线程的 suspend() 方法将该线程挂起,该线程不会释放同步监视器对象。

线程通信

wait()、notify() 方法

Condition

阻塞队列

线程池

从 JDK 1.5 开始,Java 内建支持线程池。

ForkJoinPool