Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 互斥方法_Java_Multithreading - Fatal编程技术网

Java 互斥方法

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 /

我正在学习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
        // operation 4 on map
    }
}
A类{
并行地图;
公共方法1(){
//行动1在地图上
//行动2在地图上
}
公共方法2(){
//行动3在地图上
//行动4在地图上
}
}
现在我不需要同步“someMethod1”或“someMethod2”中的操作。这意味着如果有两个线程同时调用“someMethod1”,我不需要序列化这些操作(因为ConcurrentMap将完成这项工作)

但是我希望“someMethod1”和“someMethod2”是互斥的,这意味着当某个线程正在执行“someMethod1”时,另一个线程应该等待进入“someMethod2”(但是应该允许另一个线程进入“someMethod1”)

那么,简而言之,有没有一种方法可以让“someMethod1”和“someMethod2”彼此互斥而不是互斥

我希望我的问题说得足够清楚


谢谢

这可能不起作用(请参阅评论)-留作参考


一种方法是使用:

  • 一个信号量
    sem1
    ,带有一个许可证,链接到method1
  • 一个信号量
    sem2
    ,带有一个许可证,链接到method2
当进入方法1时,尝试获得sem2的许可证,如果有,立即发布

有关实现示例,请参见

注意:在您的代码中,即使ConcurrentMap是线程安全的,操作1和操作2(例如)也不是原子的-因此在您的场景中有可能有以下交错:

  • 线程1运行操作1
  • 线程2运行操作1
  • 线程2运行操作2
  • 线程1运行操作2

这可能不起作用(请参阅评论)-留作参考


一种方法是使用:

  • 一个信号量
    sem1
    ,带有一个许可证,链接到method1
  • 一个信号量
    sem2
    ,带有一个许可证,链接到method2
当进入方法1时,尝试获得sem2的许可证,如果有,立即发布

有关实现示例,请参见

注意:在您的代码中,即使ConcurrentMap是线程安全的,操作1和操作2(例如)也不是原子的-因此在您的场景中有可能有以下交错:

  • 线程1运行操作1
  • 线程2运行操作1
  • 线程2运行操作2
  • 线程1运行操作2

首先:您的映射与它的ConcurrentMap一样是线程安全的。这意味着此映射上的操作(如add、contains等)是线程安全的

第二次 这并不能保证即使您的方法(somemethod1和somemethod2)也是线程安全的。因此,您的方法不是互斥的,两个线程可以同时访问它们


现在您希望这些操作相互互斥:一种方法可以将所有操作(操作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();
        }
    }
}