5

我正在寻找一种将功能synchronizedjava.util.concurrent.locks.ReentrantReadWriteLock. 更具体地说,我想要一种方法来仅在WriteLock设置 时锁定,但我希望锁定在对象变量上,例如synchronized. 以下是有助于解释的示例:

ReentrantReadWriteLock 示例

public void methodOne(String var) {
    lock.writeLock().lock;
    try {
        // Processing
    }
    finally {
        lock.writeLock().unlock();
    }
}

public void methodTwo(String var) {
    lock.readLock().lock;
    try {
        // Processing
    }
    finally {
        lock.readLock().unlock();
    }
}

在这个例子中,methodTwo只要writeLockonmethodOne没有被锁定,就可以在没有阻塞的情况下调用。这很好,也是我正在寻找的功能,但是当writeLock被锁定时,它在所有情况下都被锁定var。相反,我希望它只像这样var锁定synchronized

同步示例

public void methodOne(String var) {
    synchronized(var) {
        // Processing
    }
}

public void methodTwo(String var) {
    synchronized(var) {
        // Processing
    }
}

现在,这些方法只会在输入条件下阻塞。这很好,也是我正在寻找的,但是如果有多个并发调用methodTwo使用相同的键,它们会阻塞。相反,我希望这是一个“读取”样式的锁并允许调用。

本质上,我想要一个可以同步到变量以获得两组功能的 ReadWriteLock。

4

3 回答 3

5

本质上,我想要一个可以同步到变量以获得两组功能的 ReadWriteLock。

首先,根据不同值的数量,这可能会产生大量的锁。您可能会考虑进行某种分类或其他东西,以便您可以将更新划分为一个较小的数字。例如,有没有一种方法可以细分不同的 var 值。也许有各种类型的值?如果有少量固定数量的值,那么这将不是问题。

您将不得不构建某种ReentrantReadWriteLock. 也许使用ConcurrentHashMap将存储所有锁的 a 。

Map<String, ReadWriteLock> lockMap =
    new ConcurrentHashMap<String, ReadWriteLock>():
...
public void writeProcessing(String var) {
    lock = lockMap.get(var);
    lock.writeLock().lock;
    try {
       // Processing
    } finally {
       lock.writeLock().unlock();
    }
}

您需要事先注册不同的值。或者您可以按需创建它们。同样,这可能会创建一些可能令人望而却步的大量锁。

public void writeProcessing(String var) {
    lock = getLockForVar(var);
    ...
}

private ReadWriteLock getLockForVar(String var) {
   ReadWriteLock lock = lockMap.get(var);
    if (lock != null) {
        return lock;
    }
    // this might create an extra lock because of race conditions...
    lock = new ReadWriteLock();
    ReadWriteLock current = lockMap.putIfAbsent(var, lock);
    if (current == null) {
        return lock;
    } else {
        return current;
    }
}
于 2013-10-23T21:18:35.023 回答
1

如果可行,您也可以使用某种包装器。所以每个包裹的对象都会有一个唯一的锁。

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;


public abstract class ThreadSafeWrapper<T> {

  private final ReadWriteLock lock = new ReentrantReadWriteLock();
  private final T object;

  public ThreadSafeWrapper(T object) {
    this.object = object;
  }

  public final void methodOneWriteLock(String var) {
    lock.writeLock().lock();
    try {
      doMethodOne(object, var);
    } finally {
      lock.writeLock().unlock();
    }
  }

  public final void methodTwoReadLock(String var) {
    lock.readLock().lock();
    try {
      doMethodTwo(object, var);
    } finally {
      lock.readLock().unlock();
    }
  }

  protected abstract void doMethodOne(T obj, String var);

  protected abstract void doMethodTwo(T obj, String var);

}

可以这样使用:

public class SampleWrapper {

  public static void main(String[] args) {

    ThreadSafeWrapper<String> wrapper = new ThreadSafeWrapper<String>("lala") {

      @Override
      protected void doMethodOne(String obj, String var) {
        System.out.println("method one: " + obj + " " + var);
      }

      @Override
      protected void doMethodTwo(String obj, String var) {
        System.out.println("method two: " + obj + " " + var);
      }
    };

    wrapper.methodOneWriteLock("foo");
    wrapper.methodTwoReadLock("bar");

  }

}

你可以对接口做类似的事情。它只是为您指明某个方向。

于 2013-10-23T21:40:38.127 回答
0

如果我让你正确,我认为以下将有助于
解决方案,即当你要阅读它时不要同步对象,反之亦然。

public void methodOne(String var) {
    synchronized(var) {
        // Processing the writting
    }
}

public void methodTwo(String var) {
        // Processing the reading
}

我还让我提一下变量(如果有的话)的更新方法,

如果methodone要更新直接修改(如a=12name="IBM"),所以我们将省略该synchronized块,并将变量标记为volatile,但创建一个变量因为 volatile 不包括锁定读取修改更新(如a++

编辑:好的,如果你既要吃蛋糕又要吃蛋糕,我认为可能有帮助的可能是在其他东西上同步(而不是实际变量,想想pthread),你会伸出援手boolean,好吧,情况会是像这样

private volatile boolean methodOneRunning=false;
private Object readLock=new Object(),writeLock=new Object();
public void methodOne(String var) {
    synchronized(writeObject) {
        methodOneRunning=true;
        // Processing the eating
        methodOneRunning=false;
    }
}

public void methodTwo(String var) {
        if(methodOneRunning){
           synchronized(readLock){
             //having the cake
           }
        }else{
             //when thread one is not running!
        }
}

这可能是方法二开始读取,0
然后线程一在方法二进入时间后刚刚完成它的工作,1
所以这里线程二将通过锁定读取变量......,所以这可以通过另一个监控的线程来解决线程一活动并向线程二发送有关退出/终止状态的信号。

于 2013-10-23T21:15:37.073 回答