在前面的一篇中,总结了如何使用Lock和Condition对象。我们先总结一下有关锁和条件的关键之处:
Java中的每一个对象都有一个内部锁;如果一个方法用synchronized关键字声明,那么对象的锁将保护整个方法。内部对象锁只有一个相关条件,wait方法添加一个线程到等待集中,notifyAll/notify方法解除等待线程的阻塞状态。
使用synchronized的方式修改Bank类:
/** * @author XzZhao */ public class Bank { private final double[] accounts; public Bank(int n, double initialBalance) { accounts = new double[n]; for (int i = 0; i < accounts.length; i++) { accounts[i] = initialBalance; } } public synchronized void transfer(int from, int to, double amount) throws InterruptedException { while (accounts[from] < amount) { wait(); // 将该线程放到条件的等待集中 } System.out.print(Thread.currentThread()); accounts[from] -= amount; System.out.printf("转账金额: %10.2f 转出账户: %d 转入账户: %d", amount, from, to); accounts[to] += amount; System.out.printf(" 最后的金额: %10.2f%n", getTotalBalance()); notifyAll(); // 解除该条件的等待集中的所有线程的阻塞状态 } public synchronized double getTotalBalance() { double sum = 0; for (double a : accounts) { sum += a; } return sum; } public int size() { return accounts.length; } }
用synchronized关键字来写代码会简洁一些。每一个对象有一个内部锁,并且该锁有一个内部条件,由锁来管理那些试图进入synchronized方法的线程,由条件来管理那些调用wait的线程。
每一个对象有一个锁。线程可以通过调用同步方法获得锁。还有另一种方式获得锁,通过进入一个同步阻塞。
获得obj对象的锁:
synchronized (obj) { work code }
有时候,仅仅为了读写一个或两个实例域就使用同步,显得开销过大了。volatile关键字为实例域的同步访问提供了一种免锁机制。如果声明一个域为volatile,那么编译器和虚拟机就知道该域是可能被另一个线程并发更新的。
例如:
private volatile boolean result; public boolean isResult() { return result; } public void setResult(boolean result) { this.result = result; }
除非使用锁或者volatile修饰符,否则无法从多个线程安全地读取一个域。还有一种情况可以安全地访问一个共享域,就是当这个域声明为final的时候。
有可能会因为每一个线程要等待更多的钱款存入而导致所有线程都被阻塞。这样的状态称为死锁。注意还有一种很容易导致死锁的情况:就是在解除等待线程的阻塞状态时,如果只对一个线程解锁,而不是全部等待的线程。(signal 或notify)它仅仅为一个线程解锁,而且,它很可能选择一个不能继续运行的线程,这样就会出现死锁。
使用读/写锁的必要步骤:
private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); private final Lock readLock = rwl.readLock(); private final Lock writeLock = rwl.writeLock();
public double getTotalBalance(){ readLock.lock(); try{ ... }finally{ readLock.unlock(); } }
public void transfer(){ writeLock.lock(); try{ ... }finally{ writeLock.unlock(); } }
原文地址:http://blog.csdn.net/qq710262350/article/details/43274987