首页 > 解决方案 > 如何在java中请求锁定数据结构的数据

问题描述

最近,在研究现代数据库中的事务时,我发现现在的事务不会对整个集合或表使用锁或监视器,而是通常对集合或表的数据进行操作,这些数据将被不同的人使用事务执行的操作。

所以我在想,假设我们有一个数据结构,它可以是 LinkedList、Hashtable 等,并且多个不同的事务想要同时访问该结构以更新数据。我如何请求锁定事务将要使用的数据,而不是锁定整个对象数据结构?这显然会提高性能,因为使用相同数据结构的不同数据的不同更新事务将同时发生。

我将尝试澄清更多我想要实现的目标,这是一个示例:

public class Table {

    // suppose this is the data of the table and it has a lot of values
    private LinkedList<String> data = new LinkedList();

    public void doTransactionJob() {

        // here we get the data from the list
        // and we ask for monitor on this data so that no other
        // transaction can operate on it
        synchronized(data.get(randomIndex)) {
            // here the transaction works on the data but doesnt
            // block any other transaction from working on the same table
            // but with different data
        }
    }

}

是否存在与我上面的示例类似的东西?

标签: javadata-structuresconcurrencysynchronization

解决方案


您可以使用一个SynchronizedList对象,它将阻止和同步列表上的任何操作,甚至读取操作,因此在添加或更新列表时更好地使用它,或者CopyOnWriteList将使用新对象创建一个新列表,并且不会导致正在运行的读取操作的问题。但是如果你的问题是对象本身在列表中的某个位置,我建议ReentrantReadWriteLock对你想要阻止的方法使用策略,这样你可以在锁定时更好地管理,只有当人们更新对象或其他东西时,甚至使用StampedLock.

在这里你可以看到如何使用 Java 锁。您所说的“锁定事务正在使用的数据”非常含糊,您不能阻止整个对象 AFAIK,您可以阻止该对象的各个部分,一次只能通过一个线程。无论如何,如果您不想在类方法上使用锁,您可以创建第二个列表,一个已使用的对象 ID 列表,并且无法通过其他事务获取,您可以将其与lamport bakery结合使用algorithm,或将需要该对象的事务添加到队列的简单代码;

List<Object> objects = new ArrayList<>();
List<Integer> objectIds = new ArrayList<>();
Queue<Integer> transactionIds = new PriorityQueue<>();
// code ...
// suppose this is a transaction that run on a thread, and can access our lists
public void doUpdateOnObject() {
    Object object = objects.get(1);
    if (objectsIds.indexOf(object) > 0) {
        transactionIds.add(this.id) // this transactionId
        while(transactionIds.peek() != this.id) { // if you aren't the next, wait    
            Thread.sleep(400);
        }
    }
    objectIds.add(object.getId());
    // here change object fields or whatever;
    objectIds.remove(object.getId());
}

实际上,您的示例工作正常,因为它使用您要锁定的对象作为监视器,因此当一个线程位于同步块内时,没有其他线程可以访问它。


推荐阅读