Java 互斥方法
我正在学习Java多线程编程。我有以下逻辑: 假设我有一个a班Java 互斥方法,java,multithreading,Java,Multithreading,我正在学习Java多线程编程。我有以下逻辑: 假设我有一个a班 class A { ConcurrentMap<K, V> map; public void someMethod1 () { // operation 1 on map // operation 2 on map } public void someMethod2 () { // operation 3 on map /
class A {
ConcurrentMap<K, V> map;
public void someMethod1 () {
// operation 1 on map
// operation 2 on map
}
public void someMethod2 () {
// operation 3 on map
// operation 4 on map
}
}
A类{
并行地图;
公共方法1(){
//行动1在地图上
//行动2在地图上
}
公共方法2(){
//行动3在地图上
//行动4在地图上
}
}
现在我不需要同步“someMethod1”或“someMethod2”中的操作。这意味着如果有两个线程同时调用“someMethod1”,我不需要序列化这些操作(因为ConcurrentMap将完成这项工作)
但是我希望“someMethod1”和“someMethod2”是互斥的,这意味着当某个线程正在执行“someMethod1”时,另一个线程应该等待进入“someMethod2”(但是应该允许另一个线程进入“someMethod1”)
那么,简而言之,有没有一种方法可以让“someMethod1”和“someMethod2”彼此互斥而不是互斥
我希望我的问题说得足够清楚
谢谢 这可能不起作用(请参阅评论)-留作参考
一种方法是使用:
- 一个信号量
,带有一个许可证,链接到method1sem1
- 一个信号量
,带有一个许可证,链接到method2sem2
- 线程1运行操作1
- 线程2运行操作1
- 线程2运行操作2
- 线程1运行操作2
一种方法是使用:
- 一个信号量
,带有一个许可证,链接到method1sem1
- 一个信号量
,带有一个许可证,链接到method2sem2
- 线程1运行操作1
- 线程2运行操作1
- 线程2运行操作2
- 线程1运行操作2
现在您希望这些操作相互互斥:一种方法可以将所有操作(操作1,…操作4)放在一个方法中,并基于每个方法的条件调用 首先:您的映射与它的ConcurrentMap一样是线程安全的。这意味着此映射上的操作(如add、contains等)是线程安全的 第二次 这并不能保证即使您的方法(somemethod1和somemethod2)也是线程安全的。因此,您的方法不是互斥的,两个线程可以同时访问它们
现在您希望这些操作相互互斥:一种方法可以将所有操作(操作1,…操作4)放在一个方法中,并基于每个方法的条件调用 我尝试了几次更高层次的构造,但什么都没想到。我认为这可能是一个机会,让我们来看看低级别的API: 编辑:事实上,我认为您试图设置一个本质上很棘手的问题(请参见第二段至最后一段),可能不需要(请参见最后一段)。但也就是说,这是如何做到的,我将在回答的最后留下彩色注释 上述问题的一个突出问题是,它可能导致。例如,
someMethod1()
正在运行(并阻塞someMethod2()
s),就在它即将完成时,另一个线程出现并调用someMethod1()
。这一切进展顺利,当它完成时,另一个线程开始someMethod1()
,以此类推。在这种情况下,someMethod2()
将永远没有机会运行。这实际上并不是上述代码中的一个bug;这是一个与您的设计需求有关的问题,一个好的解决方案应该积极解决这个问题。我认为集市可以做到这一点,尽管这是留给读者的练习。:)
最后,我忍不住要插一句话:鉴于
ConcurrentHashMap
操作非常快,您最好在这两个方法周围放置一个互斥体,然后直接使用它。因此,是的,线程必须排队才能调用someMethod1()
,但每个线程都会非常快地完成它的任务(从而让其他线程继续)。这不应该是个问题。我尝试了几次更高层次的构造,但没有想到什么。我认为这可能是一个机会,让我们来看看低级别的API:
编辑:事实上,我认为您试图设置一个本质上很棘手的问题(请参见第二段至最后一段),可能不需要(请参见最后一段)。但也就是说,这是如何做到的,我将在回答的最后留下彩色注释
上述问题的一个突出问题是,它可能导致。例如,someMethod1()
正在运行(并阻止someMe)
private int someMethod1Invocations = 0;
private int someMethod2Invocations = 0;
public void someMethod1() {
synchronized(this) {
// Wait for there to be no someMethod2 invocations -- but
// don't wait on any someMethod1 invocations.
// Once all someMethod2s are done, increment someMethod1Invocations
// to signify that we're running, and proceed
while (someMethod2Invocations > 0)
wait();
someMethod1Invocations++;
}
// your code here
synchronized (this) {
// We're done with this method, so decrement someMethod1Invocations
// and wake up any threads that were waiting for that to hit 0.
someMethod1Invocations--;
notifyAll();
}
}
public void someMethod2() {
// comments are all ditto the above
synchronized(this) {
while (someMethod1Invocations > 0)
wait();
someMethod2Invocations++;
}
// your code here
synchronized(this) {
someMethod2Invocations--;
notifyAll();
}
}
class A {
Lock lock = new Lock();
private static class Lock {
int m1;
int m2;
}
public void someMethod1() throws InterruptedException {
synchronized (lock) {
while (lock.m2 > 0) {
lock.wait();
}
lock.m1++;
}
// someMethod1 and someMethod2 cannot be here simultaneously
synchronized (lock) {
lock.m1--;
lock.notifyAll();
}
}
public void someMethod2() throws InterruptedException {
synchronized (lock) {
while (lock.m1 > 0) {
lock.wait();
}
lock.m2++;
}
// someMethod1 and someMethod2 cannot be here simultaneously
synchronized (lock) {
lock.m2--;
lock.notifyAll();
}
}
}
public class TrafficLight<T> {
private final int maxSequence;
private final ReentrantLock lock = new ReentrantLock(true);
private final Condition allClear = lock.newCondition();
private int registered;
private int leftInSequence;
private T openState;
public TrafficLight(int maxSequence) {
this.maxSequence = maxSequence;
}
public void acquire(T state) throws InterruptedException {
lock.lock();
try {
while ((this.openState != null && !this.openState.equals(state)) || leftInSequence == maxSequence) {
allClear.await();
}
if (this.openState == null) {
this.openState = state;
}
registered++;
leftInSequence++;
} finally {
lock.unlock();
}
}
public void release() {
lock.lock();
try {
registered--;
if (registered == 0) {
openState = null;
leftInSequence = 0;
allClear.signalAll();
}
} finally {
lock.unlock();
}
}
}