如何相互排除两个程序段

时间:2017-04-30 13:16:34

标签: java multithreading concurrency

我有以下Java并发问题:

  1. 有两个功能, f1 f2 ,可以由任意线程以任意顺序执行
  2. 允许多个线程同时执行 f1
  3. 允许多个线程同时执行 f2
  4. 如果 f1 ,如果 f2 由至少一个线程执行,则不允许执行 f1 ,反之亦然 f2
  5. 现在直截了当(次优)的实现将是:

    class AccessedByManyThreads {
      void doActionWithF1() {
        foo();
        synchronized (this) {
          f1();
        }
        bar();
      }
      void doActionWithF2() {
        baz();
        synchronized (this) {
          f2();
        }
        faz();
      }
    }
    

    这个实现满足要求4.但它没有使用松弛允许的要求2.和3.实际上我需要像ReadWriteLock那样不仅可以共享读锁而且还可以写Write锁。 / p>

    所以我的问题:

    1. 我是否可以使用任何Java并发lib原语来满足要求2.和3.?
    2. 如果没有,实施的想法是什么?

2 个答案:

答案 0 :(得分:0)

我不确定是否有任何Java并发库可以帮助解决此用例。但是,您可以模拟类似于信号量变量的内容来实现此目的:

class AccessedByManyThreads {
    private int threadsAccessingF1;
    private int threadsAccessingF2;

    public AccessedByManyThreads() {
        this.threadsAccessingF1 = 0;
        this.threadsAccessingF2 = 0;
    }

    public void doActionWithF1() {
        synchronized(this) {
            if(threadsAccessingF2 > 0) {
                return;    
                // some function(s) are accessing f2, so return without calling f1()
            }
            else {
                threadsAccessingF1++;
            }
        }
        f1();
        synchronized(this) {
            threadsAccessingF1--;
        }
    }

    public void doActionWithF2() {
        synchronized(this) {
            if(threadsAccessingF1 > 0) {
                return;    
                // some function(s) are accessing f1, so return without calling f2()
            }
            else {
                threadsAccessingF2++;
            }
        }
        f2();
        synchronized(this) {
            threadsAccessingF2--;
        }
    }
}

答案 1 :(得分:0)

  1. 我认为没有标准的图书馆课程可以帮助您开箱即用。

  2. 解决方案:

  3. 这种情况可与十字路口相媲美,其中f1和f2是两条相交的道路。交通信号灯允许来自f1的流量通过或来自f2,但不允许两者同时通过。我过去遇到过这样的问题,然后构建了这个同步器类:

    public class TrafficLight<T> {
    
        private ReentrantLock lock = new ReentrantLock(true);
        private Condition switched = lock.newCondition();
        private int registered;
        private int maxBeforeYield = 20;
        private T state;
    
        public void acquire(T t) throws InterruptedException {
            lock.lock();
            try {
                while ((state != null && !state.equals(t)) || maxBeforeYield == 0) {
                    switched.await();
                }
                if (state == null) {
                    state = t;
                }
                registered++;
                maxBeforeYield--;
            } finally {
                lock.unlock();
            }
        }
    
        public void release() {
            lock.lock();
            try {
                registered--;
                if (registered == 0) {
                    state = null;
                    maxBeforeYield = 20;
                    switched.signalAll();
                }
            } finally {
                lock.unlock();
            }
        }
    }
    

    您创建一个trafficLight,并使尝试调用f1()的方法获取状态&#34; F1&#34;,并尝试调用f2()的方法获取状态&#34; F2&#34; (显然你可以使用其他状态对象。)

    如上所述,只要20个或更多线程正在等待不同的状态,该类就会强制切换状态。这基本上相当于将两个方向都设置为红灯,然后在十字路口被清除后将另一个方向设置为绿色。