(借鉴自刘望舒的Android进阶之光)
这个很好理解,有些资源是不安全的,如果多个线程同时访问会引起结果的错误,所以我们需要给他加一个同步锁。即synchronized关键字,没有人不熟悉他的,但是还有一个重入锁就比较冷门了。
Lock l = new ReentrantLock(); l.lock(); try { ... } finally { l.unlock(); }这个锁保证了同一时刻,这一个代码块(称之为临界区)只有一个线程可以进入。这里finally中解锁是很有必要的,否则如果一旦发生异常,另外所有的线程都阻塞住了。
可是当进入临界区的时候,发现只有子安一个条件满足之后,这个线程才能执行,又该怎么办。这个时候就可以用一个条件对象(别名条件变量)来管理那些已经获得了一个锁但是却不能做有用工作的线程。
一个例子说明条件对象的重要性,比如大家都在转账,这个操作必须是同步的吧。但是一旦他钱不够了怎么转给别人?这个时候难道另外的线程跟着一起死锁?所以需要把这个线程转入这个条件的等待集并置为阻塞状态,知道另一个线程调用了同一个条件的signalAll()(这是把这个条件的所有阻塞线程都开启,并且让他们在外面排队,重新竞争)为止。
public void transfer(int from, int to, int amount) throws InterruptedException{ mLock.lock(); try { while (accounts[from] < amount) { condition.await(); } accounts[from] = accounts[from] - amount; accounts[to] = accounts[to] + amount; condition.signalAll(); } finally { mLock.unlock(); } }while就是当钱不够的时候,把这个线程让条件对象来管理。下面的condition.signalAll();就是把条件对象管理的线程全部都激活,让他们重新排队。如果没有线程可以进入这个临界区,那就死锁了。
全部代码
class pay { private double[] accounts; private Lock mLock; private Condition condition; public pay(int n, double money) { accounts = new double[n]; mLock = new ReentrantLock(); condition = mLock.newCondition(); for (int i = 0; i < accounts.length; i ++) { accounts[i] = money; } } public void transfer(int from, int to, int amount) throws InterruptedException{ mLock.lock(); try { while (accounts[from] < amount) { condition.await(); } accounts[from] = accounts[from] - amount; accounts[to] = accounts[to] + amount; condition.signalAll(); } finally { mLock.unlock(); } } }
不过用synchronized锁住一个方法是更方便的选择
public synchronized void method(){ ... }用synchronized关键字来改写上面的transfer方法
public synchronized void transfer(int from, int to, int amount) throws InterruptedException { while (accounts[from] < amount) { wait(); } accounts[from] = accounts[from] - amount; accounts[to] = accounts[to] + amount; notifyAll(); }简洁很多。使用synchronized,你必须了解到每一个对象有一个内部所,并且这个锁有一个内部条件。wait().notifyAll()用法和之前的类似。
synchronized也可以通过使用同步代码块来获得这个锁。
synchronized(obj) {
}
再用这个方法改写一下
public synchronized void transfer(int from, int to, int amount) throws InterruptedException { synchronized((new Object())) { accounts[from] = accounts[from] - amount; accounts[to] = accounts[to] + amount; } }这种方法不推荐用,因为仅仅只能锁住括号里的对象,代码块是锁不了的!一般同步实现最好用comcurrent并发包下的类。