race condition
synchronize
统合了 lock 和 condition,作者认为先学后面再学前面会简单一点
Lock Objects
lock 用来锁,不让别人访问,实现对资源的互斥访问,对应 blocked
myLock.lock(); // a ReentrantLock object
try {
critical section
} finally {
myLock.unlock();
// make sure the lock is unlocked even if an exception is thrown
}
可以学一学这里 finally
的用法
不要用 try-with-resources statement.
在用 lock 的时候不要,至于为什么以后再看吧
和想象中的一样,使用同一个 lock 对象来锁,才是两者同步。(不充分,参见下文)
事实上也是这样,每个银行实例有一个自己的锁,两个线程访问了同一个银行,那自然也会用到同一个锁,此时就会被卡运行
如果是两个不同的银行,那本来就不搭嘎,不刚刚好?
为什么叫
ReentrantLock
reentrant 意为可递归的,可重入的,这表明了在同一个 thread 中,可以多次调用 lock,lock 会计数的
也就是说前面的“用同一个 lock 就锁”有些不准确,应该叫,不同线程使用同一个锁才锁
那么为什么要能递归呢?不是外面已经锁住了吗
Attention
Be careful to ensure that the code in a critical section is not bypassed by throwing an exception. If an exception is thrown before the end of the section, the finally clause will relinquish the lock, but the object may be in a damaged state.
Condition Objects
condition 用来管理已经进入互斥资源区了,但是有条件未达成无法进行下去的情况
想象这样一个情景:轮到这个银行转账,但是余额不足,就得暂时放下,让别的银行给我汇款,然后我余额就够了,然后我就接着运行了
Lock & Condition
当一个线程被阻塞,它等着获取 lock。但是一个进程被等待,此时就算它能够获得锁也不能运行,要等那个 condition 被满足
class Bank {
private Lock bankLock;
private Condition sufficientFunds;
public Bank() {
sufficientFunds = bankLock.newCondition();
}
public void transfer() {
while (!(OK to proceed))
condition.await();
// transfer
sufficientFunds.signalAll();
}
}
首先 condition 是配 lock 使用的,诞生于 lock,并且每个 lock 可以有多个 condition 为什么我还不理解,他俩区别我大概知道了,但是他俩联系我还有点不知道 大概是因为当 await 的时候,需要解锁
用一个循环包住 await,每次唤醒都要确认一下满不满足,因为别人最后都会 signalAll
一下,这一下不保证可行,所以就要让 await 处试试了
signalAll
放在对 waiting 线程有帮助的代码执行后,并且不是立马执行,只是不被阻塞了,所以回去排队了
Attention
A thread can only call await, signalAll, or signal on a condition if it owns the lock of the condition.
没理解深意
The synchronized Keyword
Java 每个类都自带一个锁,叫 this.intrinsicLock
,和配套的一个 condition,叫 intrinsicCondition
而锁一般是锁住整个方法,所以加了 synchronized
关键字后,默认加锁;但是 condition 要自己灵活运用,所以封装了 wait
, notifyAll
, notify
class Bank {
private double[] accounts;
public synchronized void transfer(int from, int to, int amount) throws InterruptedException {
while (accounts[from] < amount)
wait(); // wait on intrinsic object lock's single condition
accounts[from] -= amount;
accounts[to] += amount;
notifyAll(); // notify all threads waiting on the condition
}
public synchronized double getTotalBalance() { . . . }
}
static synchronized
此时用的是 type.class
obj 内的 intrinsicLock
,这使得这个静态方法别的 thread 用不了,同类的别的静态方法也用不了 (仔细想想,就是因为用的同一个 lock 嘛)
Synchronized Blocks
synchronized (obj) { // this is the syntax for a synchronized block
critical section
}
then it acquires the lock for obj. 我感觉我喜欢这串英文,很明了。得了谁的锁,谁就是互斥资源。这是一个 “ad hoc” locks (md 拉丁语啊,什么表示特殊解决)
但他要求使用的类的每个修改方法都是被 synchronized 了的
As you can see, client-side locking is very fragile and not generally recommended.
recommend
- 首先是最好别用,实际上 Thread-Safe Collections 可以绕开使用
- 其次要用也用 synchronized,简单不易出错
- 最后实在有什么个性化再去用 lock/condition