简体   繁体   English

使用双计数器在Java中进行同步

[英]Using double counters to synchronize in Java

I have a strange synchronization architecture going on and I am looking for an elegant solution. 我正在使用一种奇怪的同步体系结构,并且正在寻找一种优雅的解决方案。 I already had a solution but I cannot say anything about its validity and its also a little ugly. 我已经有一个解决方案,但是我不能说出它的有效性和丑陋之处。 So here is the problem, hopefully someone can help me. 这就是问题所在,希望有人可以帮助我。

There are 2 groups of tasks that can be started and run. 可以启动和运行2组任务。 Each task has its own thread. 每个任务都有其自己的线程。 These two groups both extend from one super class that takes care of the synchronization part. 这两类都从一个负责同步部分的超类扩展而来。 I will call these two groups Group A and Group B for simplicity. 为了简单起见,我将这两个组称为A组和B组。

Conditions: 条件:

  • If there are only Group B tasks running then they can run at the same time and they do not interfere with each other. 如果只有B组任务正在运行,则它们可以同时运行,并且不会互相干扰。

  • If a Group A task is started* then the constructor for a Group B task should fail with an exception. 如果启动了A组任务*,则B组任务的构造函数将失败,并出现异常。 Any number of Group A tasks can be created even if a Group A task is already running 即使已经运行A组任务,也可以创建任意数量的A组任务

  • A Group A task cannot execute until all current Group B tasks have finished. 在所有当前的B组任务完成之前,A组任务无法执行。 (* from above) (* 从上面)

  • Only 1 Group A task can run at a time. 一次只能执行1个A组任务。 They must be queued. 他们必须排队。 (It is optional to block Group B tasks between the running of the two Group A tasks as long as the previous conditions still apply) (可以选择在两个A组任务的运行之间阻止B组任务,只要符合上述条件即可)

I believe my method works but I do not like the way it works because of the many different synchronization points that it uses, and the fact that I have a sleep while waiting for the counter. 我相信我的方法有效,但是由于它使用了许多不同的同步点,并且我在等待计数器时睡眠,因此我不喜欢它的工作方式。 Anyway the code is below 反正代码在下面

public abstract class LockableTask<Params> extends AsyncTask {

private final boolean groupA;
private static Boolean locked = false;
private static final Semaphore semLock = new Semaphore(1);
private static int count = 0;

public LockableTask(boolean groupA) {
    this.groupA = groupA;
    synchronized (locked) {
        if (locked && !groupA) {
            throw new InputException("We are locked, please wait");
        }
    }
}

@Override
protected final AsyncReturn doInBackground(Params... params) {
    if (!groupA) {
        synchronized (locked) {
            count++;
        }
    }

    try {
        if (groupA) {
            semLock.acquireUninterruptibly();
            synchronized (locked) {
                locked = true;
            }

            while (true) {
                synchronized (locked) {
                    if (count == 0) {
                        break;
                    }
                }

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {}
            }
        }
        return runInBackground(params);
    } finally {
        synchronized (locked) {
            if (groupA) {
                locked = false;
            } else {
                count--;
            }
        }

        if (groupA) {
            semLock.release();
        }
    }
}

protected abstract AsyncReturn runInBackground(Params... params);
}

If someone has a nicer solution even if just barely nicer that would be great 如果有人有更好的解决方案,哪怕只是勉强更好,那也很好

Sounds like you want to use a ReadWriteLock . 听起来好像您想使用ReadWriteLock Let each task of group A acquire its readLock() and each task of group B acquire its writeLock() . 让A组的每个任务获取其readLock()而B组的每个任务获取其writeLock()

This way any number of Group A tasks can run at once, but only ever one task of Group B can run (at which point no other Group A tasks can run). 这样,任何数量的A组任务都可以一次运行,但是B组中只有一个任务可以运行(此时其他A组任务都不能运行)。

ReadWriteLock rwLock = getSharedReadWriteLock();
Lock lock = groupA ? rwLock.readLock() : rwLock.writeLock();
lock.lock();
try {
  return runInBackground(params);
} finally {
  lock.unlock();
}

If you have an upper bound on the number of simultaneous Group B tasks (even if it's very large), you should be able to achieve the rules you describe with a single semaphore. 如果同时B组任务的数量有上限(即使很大),则应该能够使用单个信号量实现描述的规则。

int UPPER_BOUND=1000000;
Semaphore s=new Semaphore(UPPER_BOUND);

Group A task: A组任务:

s.acquireUninterruptibly(UPPER_BOUND);
......
s.release(UPPER_BOUND);

Group B task: B组任务:

if (!s.tryAcquire())
    throw new WhateverException("Upper bound of Bs reached or A running");
......
s.release();

End result: whilst any group B are running, A cannot acquire the number of permits it requires. 最终结果:在任何B组运行时,A无法获得所需的许可数量。 Once it does, no B can acquire a permit and neither can any other A. 一旦这样做,任何B都不会获得许可,其他任何A都不会。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM