2018-01-03
因为线程的运行与休眠,是由操作系统控制的,存在很大的随机性。因线程不安全而造成的bug,每次出现的时间,产生的现象都可能不同,因此往往很难定位。所以在写多线程的程序时,一定要确保自己的代码是线程安全的。
一、同步 synchrony
在多线程程序中,为了防止因多个线程随机修改同一个变量,而引入锁机制,实现线程间的同步。
ReentrantLock类(reentrant可重入的),实现了 lock 接口。
-
同步格言:**如果从一个变量读值,而这个变量可能是之前被其他线程修改了的,或者,向一个变量写入值,而这个变量接下来可能被其他线程读取。那么必须确保这个操作是同步的(synchronous)。 **
-
确保同步的方法:
-
首选是使用 java.util.concurrent 包中的线程安全的机制来自动处理同步。
-
使用 synchronized 关键字 修饰线程不安全的方法 / 构造同步代码块。
-
内部锁Lock与内部条件Condition:实例的 Synchronized 方法,实际上是使用了this对象做为锁。如果用这个Runnable对象创建了多个线程,任意线程调用这个方法时,会先试图获取这个this对象锁。离开时会先释放this锁。(而静态的 sync 方法使用 的锁,则是其所从属的class对象。)
-
Synchronized 代码块:将传入的对象做为锁
-
使用 Volatile 关键字 修饰线程不安全的变量(译:反复无常的)
-
Lock 和 Condition,因为锁与条件都对程序员开放,被认为更不安全。所以一般建议只在需要使用多个Condition时,才使用它。(sync方法只有一个内部condition)
-
-
线程安全的条件:如果出现了问题,一定是两个条件中的一个不满足。
- 需要同步的线程必须使用的是同一把锁。否则后来的线程不会因此被阻塞。
- 所有线程不安全的代码(即 c. 中所言的操作代码)都已经是同步的了。
-
死锁:
二、异步 asynchrony
大部分语言都是通过 coroutine 实现的异步,Java 本身目前并没有很好的异步工具。