Lock 是Java多线程的一个同步机制,用来控制线程对共享资源的访问。线程在执行同步方法或者代码块之前必须先获得一个锁。
Lock 的 lock() 和 unlock() 方法;
lock():获得一个锁,如果锁不可用,则当前线程将因线程调度目的而被禁用,并在获得锁之前处于休眠状态。
unlock():释放掉获得的锁。
Lock的作用范围:
-
若 Lock 是静态的,则作用范围是整个类。
public class Test { public static void main(String[] args) { Thread thread_one = new Thread(new Account(), "Thread_ONE"); Thread thread_two = new Thread(new Account(), "Thread_Tow"); thread_one.start(); thread_two.start(); } } class Account implements Runnable{ static Lock lock = new ReentrantLock(); // 静态的Lock static int Count = 0; @Override public void run(){ runTest(); } public void runTest() { lock.lock(); try{ for(int i = 0; i < 5; ++i) { Count++; System.out.println(Thread.currentThread().getName() + " " + Count); } } finally { lock.unlock(); } } } //输出: //Thread_ONE 1 //Thread_ONE 2 //Thread_ONE 3 //Thread_ONE 4 //Thread_ONE 5 //Thread_Tow 6 //Thread_Tow 7 //Thread_Tow 8 //Thread_Tow 9 //Thread_Tow 10
-
若 Lock 是非静态的,则范围是整个对象。
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Test1 { public static void main(String[] args) { Thread thread_one = new Thread(new Account(), "Thread_ONE"); Thread thread_two = new Thread(new Account(), "Thread_Tow"); thread_one.start(); thread_two.start(); } } class Account implements Runnable{ Lock lock = new ReentrantLock(); // 非静态的Lock static int Count = 0; @Override public void run(){ runTest(); } public void runTest() { lock.lock(); try{ for(int i = 0; i < 5; ++i) { Count++; System.out.println(Thread.currentThread().getName() + " " + Count); } } finally { lock.unlock(); } } } //输出: //Thread_Tow 2 //Thread_ONE 2 //Thread_Tow 3 //Thread_ONE 4 //Thread_Tow 5 //Thread_ONE 6 //Thread_Tow 7 //Thread_ONE 8 //Thread_Tow 9 //Thread_ONE 10
Lock的一个简单的实现
public class Lock{ private boolean isLocked = false; public synchronized void lock()throws InterruptedException{ while(isLocked){ // 使用whlie而不是if wait(); // 终止线程并且释放对象的锁,当线程被通知后重新启动,锁就会自动被重新获取 } isLocked = true; } public synchronized void unlock(){ isLocked = false; notify();//通知一个等待的线程重新获取锁并且恢复执行 } }
这里的方法lock(),若当前的锁被其它线程获取而锁住,这调用wait()方法,让线程等待,直到其他线程调用unlock()中的notify()方法而重新启动。这里用的是while而不是if,防止wait()退出后锁还是被其它线程锁住,(比如锁又被其它线程抢走),(lock() 和 notify()、notifyAll() 是Object对象中的方法)
ReentrantLock 是 Lock接口 的一种实现。
public class ReentrantLock implements Lock, java.io.Serializable{ }
ReentrantLock 具有可重入性。
什么是可可重入性呢?先举个例子。
public class Reentrant2{ Lock lock = new Lock(); // 这里的Lock用的是上面写的 public class Lock { } public outer(){ lock.lock(); inner(); lock.unlock(); } public synchronized inner(){ lock.lock(); //do something lock.unlock(); } }
假设某个线程调用了outer()方法,这时,该线程调用了lock(),获取了锁,然后再调用inner(),但是inner()内再次调用 lock() 获取锁,可是这锁已经被第一次调用而锁上,所以会进入while调用wait()从而导致死锁。
可重入性可以让线程调用自身持有的锁(如果该锁是可重入的)。
改写一下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(); } } } ... }
while 循环中加了一个判断 lockedBy != callingThread,这样就不会被自己的锁锁住,并且用 lockedCount 计数一下,只有当 lockedCount 为 0 时,才会调用notify()方法。
最后说一点,使用锁的时候最好使用try,以防一些想不到的问题导致锁没有释放。
lock.lock(); try{ //do critical section code, which may throw exception } finally { lock.unlock(); }
参考:http://tutorials.jenkov.com/java-concurrency/locks.html