[1]-1 Locks in Java
来源:互联网 发布:js给div添加class 编辑:程序博客网 时间:2024/06/06 16:31
Locks in Java
Jakob Jenkov
Last update: 2014-06-23
A lock is a thread synchronization mechanism like synchronized blocks except locks can be more sophisticated 【复杂】 than Java's synchronized blocks. Locks (and other more advanced synchronization mechanisms) are created using synchronized blocks, so it is not like we can get totally rid 【摆脱,解除】 of the synchronized
keyword.
From Java 5 the package java.util.concurrent.locks
contains several 【几个,一些】lock implementations, so you may not have to implement your own locks. But you will still need to know how to use them, and it can still be useful to know the theory behind their implementation. For more details, see my tutorial on the java.util.concurrent.locks.Lock
interface.
lock它是一个类似于synchronized 块的线程同步机制,但是lock比synchronized 块更复杂一些。
Locks(包括其他高级的同步机制)是使用synchronized 块创建的,因此我们不可能摆脱synchronized 块关键词。
从Java 5 开始,java.util.concurrent.locks包包含了几个lock的实现,因此你可以不需要自己去实现自己的lock。但是你仍然需要学习如何使用它,而且爱了解他们的实现前学习他们的理论。
A Simple Lock
Let's start out by looking at a synchronized block of Java code:
public class Counter{ private int count = 0; public int inc(){ synchronized(this){ return ++count; } }}
Notice the synchronized(this)
block in the inc()
method. This block makes sure that only one thread can execute the return ++count
at a time. The code in the synchronized block could have been more advanced, but the simple ++count
suffices 【足够,满足...的需要】 to get the point across 【讲清楚;报名重点】.
The Counter
class could have been written like this instead 【太低,顶替,反而】, using a Lock
instead of 【(用…)代替…, (是…)而不是…,】 a synchronized block:
译文:
一个简单的Lock
注意在inc()方法中的synchronized(this)块。
这个synchronized(this)块能够确保每次只有一个线程可以执行 return ++count 。
在synchronized(this)块中的代码还可以更高级,但是简单的++count
已经足够把这点说清楚。
Counter
class 还可以这样写,使用一个lock代替synchronized 块。
public class Counter{ private Lock lock = new Lock(); private int count = 0; public int inc(){ lock.lock(); int newCount = ++count; lock.unlock(); return newCount; }}
The lock()
method locks the Lock
instance so that all threads calling lock()
are blocked until unlock()
is executed.
Here is a simple Lock
implementation:
译文:
lock()方法锁住了Lock
对象,因此所有其他线程调用lock()都是被阻塞的除非unlock()
被执行。
下面是一个简单的Lock实现:
public class Lock{ private boolean isLocked = false; public synchronized void lock() throws InterruptedException{ while(isLocked){ wait(); } isLocked = true; } public synchronized void unlock(){ isLocked = false; notify(); }}
Notice the while(isLocked)
loop, which is also called a "spin lock" 【自旋锁】. Spin locks and the methods wait()
and notify()
are covered in more detail in the text Thread Signaling. 【线程通信】
While isLocked
is true, the thread calling lock()
is parked waiting in the wait()
call.
In case the thread should return unexpectedly 【未预料到的】 from the wait() call without having received a notify()
call (AKA a Spurious Wakeup 【虚假唤醒】) the thread re-checks 【双重检查、重新检查】 the isLocked
condition to see if it is safe to proceed or not, rather than 【而不是】 just assume 【假定】 that being awakened means it is safe to proceed. If isLocked
is false, the thread exits the while(isLocked)
loop, and sets isLocked
back to true, to lock the Lock
instance for other threads calling lock()
.
When the thread is done with the code in the critical section 【临界资源】(the code between lock()
and unlock()
), the thread calls unlock()
. Executing unlock()
sets isLocked
back to false, and notifies (awakens) one of the threads waiting in the wait()
call in the lock()
method, if any.
译文:
注意到 while(isLocked)循环,它也被叫做
自旋锁
。自旋锁和wait()方法、notify()在 Thread Signaling. 【线程通信】 中都有涉及。
只要
isLocked
是true,调用lock()方法的线程停在 wait()方法。
In case the thread should return unexpectedly 【未预料到的】 from the wait() call without having received a
notify()
call (AKA a Spurious Wakeup 【虚假唤醒】) the thread re-checks 【双重检查、重新检查】 the isLocked
condition to see if it is safe to proceed or not, rather than 【而不是】 just assume 【假定】 that being awakened means it is safe to proceed. If isLocked
is false, the thread exits the while(isLocked)
loop, and sets isLocked
back to true, to lock the Lock
instance for other threads calling lock()
.
当线程在临界资源(the code between
lock()
and unlock()
)的代码完成时,线程调用unlock()方法。执行
unlock()
方法 设置 isLocked
为 false ,然后notifies (awakens) 通知(唤醒)一个在wait()中的线程去调用lock()方法。
Lock Reentrance
Synchronized blocks in Java are reentrant. This means, that if a Java thread enters a synchronized block of code, and thereby take the lock on the monitor object the block is synchronized on, the thread can enter other Java code blocks synchronized on the same monitor object. Here is an example:
译文:Lock Reentrance 可重入锁
Synchronized 块在java中是可重入的。这就意味着,如果一个线程进入了一个Synchronized 代码块,因此拿到了Synchronized 代码块的监控对象的锁,那么,这个线程也可以进入其他的持有同一个监控对象的锁的代码块。下面的一个例子:
public class Reentrant{ public synchronized outer(){ inner(); } public synchronized inner(){ //do something }}
Notice how both outer()
and inner()
are declared synchronized, which in Java is equivalent to a synchronized(this)
block.
If a thread calls outer()
there is no problem calling inner() from inside outer()
, since both methods (or blocks) are synchronized on the same monitor object ("this").
If a thread already holds the lock on a monitor object, it has access to all blocks synchronized on the same monitor object. This is called reentrance. The thread can reenter any block of code for which it already holds the lock.
The lock implementation shown earlier is not reentrant. If we rewrite the Reentrant
class like below, the thread calling outer()
will be blocked inside the lock.lock()
in the inner()
method.
outer()
方法和 inner()方法都声明了synchronized。在java里这等同于synchronized(this)块。
If a thread calls outer()
there is no problem calling inner() from inside outer()
, since both methods (or blocks) are synchronized on the same monitor object ("this").
如果一个线程调用 outer()方法
Reentrant
,线程调用 outer() 方法时将会阻塞 inner()方法的lock.lock();public class Reentrant2{ Lock lock = new Lock(); // 注意 此处的 Lock 自己实现的锁,而不是java.util.concurrent.locks.Lock
public outer(){ lock.lock(); inner(); lock.unlock(); } public synchronized inner(){ lock.lock(); //do something lock.unlock(); }}
A thread calling outer()
will first lock the Lock
instance. Then it will call inner()
. Inside the inner()
method the thread will again try to lock the Lock
instance. This will fail (meaning the thread will be blocked), since the Lock
instance was locked already in the outer()
method.
The reason the thread will be blocked the second time it calls lock()
without having called unlock()
in between, is apparen 【显然,明显】t when we look at the lock()
implementation:
译文:
调用outer()方法的线程首先会获取
Lock
实例的锁。然后将会调用inner() 。在inner()方法内部线程会再次尝试去获取Lock
示例的锁,但是将会失败(意味着线程会被阻塞)。因此Lock
实例在outer()
方法内部已经被锁。
在没有调用unlock()时线程将会在第二次调用lock()时阻塞。看看我们实现的lock()方法的实现就很明显。
public class Lock{ boolean isLocked = false; public synchronized void lock() throws InterruptedException{ while(isLocked){ wait(); } isLocked = true; } ...}
It is the condition inside the while loop (spin lock) that determines 【确定;决定;规定;【物】测定】 if a thread is allowed to exit the lock()
method or not. Currently the condition is that isLocked
must be false
for this to be allowed, regardless 【不顾;不加理会,无论】of what thread locked it.
To make the Lock
class reentrant we need to make a small change:
lock()
方法。isLocked
为false才能退出lock()
方法。Lock
是可重入的,我们需要做些改动:public class Lock{ boolean isLocked = false; Thread lockedBy = null; int lockedCount = 0; public synchronized void lock() throws InterruptedException{ Thread callingThread = Thread.currentThread(); while(isLocked && lockedBy != callingThread){ wait(); } isLocked = true; lockedCount++; lockedBy = callingThread; } public synchronized void unlock(){ if(Thread.curentThread() == this.lockedBy){ lockedCount--; if(lockedCount == 0){ isLocked = false; notify(); } } } ...}
Notice how the while loop (spin lock) now also takes the thread that locked the Lock
instance intoconsideration 【顾及;报酬;斟酌;仔细考虑】.
If either the lock is unlocked (isLocked
= false) or the calling thread is the thread that locked the Lock
instance, the while loop will not execute, and the thread calling lock()
will be allowed to exit the method.
Additionally 【另外】, we need to count the number of times the lock has been locked by the same thread. Otherwise 【否则;不然;另;除此以外】, a single call to unlock()
will unlock the lock, even if 【即使…也】the lock has been locked multiple times. We don't want the lock to be unlocked until the thread that locked it, has executed the same amount of unlock()
calls as lock()
calls.
The Lock
class is now reentrant.
Lock
对象的线程。unlock()
和 lock()。
Lock Fairness
Java's synchronized blocks makes no guarantees 【grant准予;授予;同意 保证;抵押品;保证人;接受保证的人】 about thesequence 【顺序;次序;一系列;一连串】 in which threads trying to enter them aregranted 【准予;授予;同意】 access. Therefore 【所以;因而;为此】, if many threads areconstantly 【经常地;不变地;不断的】 competing 【compete 竞争;竞赛;比得上;参加比赛(或竞赛)】 for access 【通道;入口;机会;权力】 to the same synchronized block, there is a risk 【风险;危险;危险人物;会带来风险的事物】 that one or more of the threads are never granted access - that access is always granted to other threads. This is called starvation 【饥饿;饿死;挨饿】. To avoid 【避免;避开;防止;回避】 this a Lock
should be fair. Since 【因为;由于;既然;从…以后】 the Lock
implementations shown in this text uses synchronized blocks internally 【内部的;体内的】, they do not guarantee fairness. Starvation and fairness are discussed 【讨论;论述;议论】 in more detail in the text Starvation and Fairness.
Lock Fairness Lock 公平性
java的synchronized 块没有保证线程进入授权接口的顺序。Calling unlock() From a finally-clause
When guarding a critical section with a Lock
, and the critical section may throw exceptions, it is important to call the unlock()
method from inside a finally
-clause. Doing so makes sure that the Lock
is unlocked so other threads can lock it. Here is an example:
lock.lock();try{ //do critical section code, which may throw exception} finally { lock.unlock();}
This little construct makes sure that the Lock
is unlocked in case an exception is thrown from the code in the critical section. If unlock()
was not called from inside a finally
-clause, and an exception was thrown from the critical section, the Lock
would remain locked forever, causing all threads calling lock()
on that Lock
instance to halt 【停止;暂停;中断;常用于英式英语】indefinately 【无限期地;〔化〕无限期地;无限制地;稳定;遥遥无期地;不定期地】.
Calling unlock() From a finally-clause 在finally 子句中调用 unlock() 方法
当为一个临界区使用锁时,临界区的代码可能会抛出异常。
lock.lock();try{ //do critical section code, which may throw exception} finally { lock.unlock();}
- [1]-1 Locks in Java
- [1]-2 Read - Write Locks in Java
- Read / Write Locks in Java
- java.util.concurrent.locks 并发包介绍【1】
- JDK5并发(1) Locks-AQS
- Locks in Oracle
- Locks In Synchronized Methods
- java.util.concurrent.locks.Locks和synchronized
- Java Explicit Locks
- java.util.concurrent.locks
- java.util.concurrent.locks简述
- java.util.concurrent.locks Synchronized
- java.util.concurrent.locks.ReentrantLock
- java.util.concurrent.locks.AbstractOwnableSynchronizer
- java.util.concurrent.locks.Lock
- java.util.concurrent.locks.LockSupport
- 软件包 java.util.concurrent.locks
- Java.concurrent.locks(2)-ReentrantLock
- Step1 Volley 框架介绍
- MyEclipse2014快速搭建hibernate开发环境及快速由表生成POJO类步骤
- 【数据结构】AVL树
- android studio 引用 so库
- 第80篇 webrtc一对一研究(九)及php
- [1]-1 Locks in Java
- ④sqlilabs的less-3和less-4
- python合并txt
- 关于Linux系统分区的简单说明
- JS面向对象(一)
- Unix软件包管理
- 支付宝即时到帐接口的python实现,示例采用django框架
- [1]-2 Read - Write Locks in Java
- BFS——刀耕火种