线程同步 提供了两种策略java
Synchronized Methodssegmentfault
Synchronized Statementsapp
本文介绍 Synchronized Statementsthis
不过,须要先了解一下 Intrinsic Locks线程
同步机制的实现,是围绕被称为 intrinsic lock 的内部实例实现的。Intrinsic lock 在同步机制中发挥两个做用:强制独占访问对象状态的权限,并创建可见的 happens-before 关系code
每个对象都有一个 intrinsic lock 与之关联。通常的,一个须要独占某对象的访问权限的线程,在访问该对象的资源以前,须要请求这个对象的 intrinsic lock,并在访问结束后释放该 intrinsic lock 。在获取 lock 到释放 lock 这之间,该线程拥有该 intrinsic lock 。只要一个线程拥有 intrinsic lock,其余线程将不会获取该 lock 。当试图请求一个已经被独占的 lock 时,其余线程将会阻塞 。对象
当一个线程释放 intrinsic lock,该动做将会与随后的获取 lock 的请求之间,创建一个 happens-before 关系 —— 即随后的被阻塞的线程,能够得知 lock 已被释放。资源
当一个线程调用一个对象的 synchronized method,该线程将自动获取这个对象的 intrinsic lock,而后在方法 return 时释放 lock 。即便 method 是由于没有 catch 的 exception 而返回, 也会释放 lockget
BTW: 当调用一个 static synchronized method 时(即该方法与一个类关联,而不是一个对象),会发生什么?线程会向该类的 Class 对象请求 intrinsic lock。同步
实现线程同步的另外一种方法,就是使用 Synchronized Statements。
与 Synchronized Methods 不一样,Synchronized Statements 不能自动获取对象的 intrinsic lock,而是必须明确指明提供了 intrinsic lock 的对象(这也是 Synchronized Statements 的优势,稍后会提到)
例子:
public void addName(String name) { synchronized(this) { lastName = name; nameCount++; } nameList.add(name); }
上边的例子中,不一样线程调用 addName 方法在修改 lastName 和 nameCount 时,将会同步。在调用 nameList.add 方法时将不会进行同步。
再说一个例子。假定类 MyLunch 有两个字段 c1 和 c2,且这两个字段毫不会用在一块儿。全部对 c1 和 c2 的修改都必须分别同步,但不必再修改 c1 时避免对 c2 的修改,反而使得程序效率不高。
所以,不使用 Synchronized Methods 或 synchronized (this),而是独立的建立两个对象,提供各自独立的 intrinsic lock
public class MsLunch { private long c1 = 0; private long c2 = 0; private Object lock1 = new Object(); private Object lock2 = new Object(); public void inc1() { synchronized(lock1) { c1++; } } public void inc2() { synchronized(lock2) { c2++; } } }
一个线程不能请求到一个已经被其它线程占用的 lock,但一个线程能够请求到一个已经被本身占中的 lock。