java尝试终于解开成语

时间:2016-07-31 13:09:14

标签: java multithreading locking try-finally

Javadoc和一些答案(Threads - Why a Lock has to be followed by try and finally)声明:

在大多数情况下,应使用以下习语:

 Lock l = ...;
 l.lock();
 try {
     // access the resource protected by this lock
 } finally {
     l.unlock();
 }

我在标准Java库中看到过这个习惯用法的例子。 这是我使用它的例子。字段acc1和acc2代表一个众所周知的银行帐户示例。主要约束是acc的值的总和 - 它应该是0.

public class Main {
    int acc1;
    int acc2;

    ReadWriteLock lock = new ReentrantReadWriteLock();

    public int readSum() {
        lock.readLock().lock();
        try {
            return acc1 + acc2;
        } finally {
            lock.readLock().unlock();
        }
    }

    public void transfer() {
        lock.writeLock().lock();
        try {
            acc1--; // constraint is corrupted
                    // exception throwed here
            acc2++; // constraint is regained
        } finally {
            lock.writeLock().unlock();
        }
    }
}

我理解在读取情况下使用成语:如果在read方法中抛出异常,其他线程仍然可以读/写一致资源。但是如果在write方法中抛出的excteption读取方法可以读取不一致的资源。

为什么读取不一致的值比无限锁等待更合适? 为什么Java库作者更喜欢这种行为?

2 个答案:

答案 0 :(得分:0)

你在这里混淆了不同的概念。有:

  1. 锁定,防止死锁,然后
  2. 另一个维度,我们称之为“数据完整性”。
  3. 关键点:这两者基本上是正交的。你正在解决其中一个问题的事实并没有为你神奇地解决另一个问题!

    即使你看看你自己的例子,你也会发现你在那里试了一下。但那里没有 catch ! 尽一切代价 含义:如果抛出某个异常,仍会抛出该异常,并且一些捕获者将不得不处理它。

    换句话说:如果你的“锁定”代码可以遇到异常,那么你有责任以最有意义的方式处理它。

    并且,从“系统”视图:当您获得无限期锁定时,迟早会降低整个系统的性能。如果您遇到一次该异常,那么您将更频繁地遇到它。所以,很可能你很快就会用完线程/锁;并且您的整个申请将受到影响。这正是可以解决分布式基础架构的问题 - 一个组件停止处理传入的请求。

    长话短说:无限锁等待是你要防止的,因为它会严重影响你的应用程序运行的能力!

    最后:当然,这是关于不同要求的平衡。但是,例如:假设您的在线商店丢失了您刚刚从购物车中删除商品的信息。是的,这对客户来说很烦人。但比较一下:整个在线购物应用程序停止处理请求;因为锁定问题。哪个问题会伤害您的业务?

答案 1 :(得分:0)

您可以回滚或向用户提供一些警告信息,但如果程序被阻止,则无法执行任何操作。

我同意你所谈论的data consistency。在没有任何回滚操作或警告的情况下解锁最终部分是危险的。