###翻譯自 [Jakob Jenkov](http://tutorials.jenkov.com/java-concurrency/locks.html#simple-lockhtml
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.java
//JAVA5以來,在java.util.concurrent.locks包中提供了若干種鎖的實現,因此因此你可能沒必要實現你本身的鎖。可是你須要知道如何使用它們,而且知道實現後面的原理。經過下面的代碼塊,看我關於鎖的教程。安全
A Simple Lockapp
Let's start out by looking at a synchronized block of Java code:less
一個簡單的鎖 讓咱們先來看看一個同步的代碼塊ide
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.oop
這裏是一個自增的同步代碼塊,每當執行一個線程時,返回++count。這個代碼快能夠寫得更完善,可是用於++count計算已經徹底足夠了。ui
The Counter class could have been written like this instead, using a Lock instead of a synchronized block:this
這個計數器類可能鎖下面這樣寫的,使用一個鎖替代同步代碼塊;線程
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. 這個鎖的方法lock() 能讓實例lock阻塞直到unlock()方法被調用
Here is a simple Lock implementation: 下面是一個簡單的鎖的實現:
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().
在循環while(isLocked)中,也被稱爲「自旋鎖」,自旋鎖和方法wait()、方法notify() 中有線程實現的細節。當islocked爲true時,線程訪問lock()方法停在wait()處。若是線程一直沒有收到來自notify()的喚醒信號,線程從新檢查鎖條件是否安全的進行與否,而不是直接將其喚醒。若是islocked爲false,線程推出循環,而且設置islocked爲true,將其返回,而後在其餘線程調用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.
當線程在臨界區的代碼完成時(在lock()和unlock()之間),將訪問unlock(),執行unlock() 設置 isLocked爲false並返回,喚醒一個正在等待的線程執行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:
同步代碼塊在java裏時折返。意思鎖: 若是java線程中進入了一個同步代碼塊,從而鎖住了一個監控的對象,這個線程能在統一個監控對象中輸入其餘的java代碼塊。 下面是一個例子:
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.
請注意outer()和inner()聲明Java同步,這至關於一個同步塊(本)。若是一個線程調用outer()有從內outer()調用inner()沒有問題,由於這兩種方法(或塊)同步,在同一監測對象(「本身」)。若是一個線程已將鎖放在監視器對象上,它能夠在同一監視對象上同步訪問全部的塊。這就是所謂的折返。線程能夠進入任何代碼塊,它已經持有的鎖。
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.
這個鎖的是不可折返的。若是咱們改寫Reentrant類像下面這樣,線程調用OUT方法將被inner方法中的鎖阻擋住;
public class Reentrant2{ Lock lock = new 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.
一個線程訪問outer()會鎖住Lock實例,再訪問inner(),在inner方法裏將再次對Lock進行上鎖,這會失敗(即線程會被阻塞),因爲鎖的實例已經鎖在outer()方法。
The reason the thread will be blocked the second time it calls lock() without having called unlock() in between, is apparent when we look at the lock() implementation:
緣由的線程將被阻塞,這是它第二次訪問lock()沒有叫unlock()之間,很明顯當咱們看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.
它是在while循環的條件(自旋鎖)決定若是一個線程是容許退出lock()法與否。公用的條件isLocked必須鎖false才被容許,不管如何,線程都會被鎖住。
To make the Lock class reentrant we need to make a small change:
如今想讓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 into consideration. 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.
通知自旋鎖如今還須要讀取Lock實例的條件(配置),若是isLocked爲false 或者 調用線程的線程鎖Lock實例,這個while不會執行,而且線程調用lock方法將被容許推出方法。
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.
此外,咱們須要計算鎖的次數,該鎖已被相同的線程鎖。不然,一個信號來unlock()會打開鎖,即便鎖已經被屢次。咱們不想將鎖打開,直到線程鎖,執行unlock()調用相同lock()。 LOCK類如今能夠折返了。
###英語渣渣...
serveral //若干種 implementations //實現 theory //原理 tutorial //教程 details //細節 advanced //先進 suffices //足夠 instead //替代 parked //停 proceed //進行 critical //臨界 like below //相似下面 reason //緣由 determines //使..下決定 regardless //不管如何