Использование двойных счетчиков для синхронизации в Java - PullRequest
0 голосов
/ 11 марта 2011

У меня странная архитектура синхронизации, и я ищу элегантное решение.У меня уже было решение, но я не могу ничего сказать о его обоснованности, а также о том, что оно немного уродливо.Так что вот в чем проблема, надеюсь, кто-то может мне помочь.

Есть две группы задач, которые можно запускать и запускать.У каждой задачи есть свой поток.Эти две группы являются частью одного суперкласса, который занимается синхронизацией.Для простоты я назову эти две группы группой A и группой B.

Условия:

  • Если выполняются только задачи группы B, они могут выполняться одновременнои они не мешают друг другу.

  • Если запускается задача группы A *, тогда конструктор для задачи группы B должен завершиться сбоем с исключением.Можно создать любое количество задач группы A, даже если задача группы A уже запущена

  • Задача группы A не может быть выполнена до тех пор, пока все текущие задачи группы B не будут завершены.(* сверху)

  • Одновременно может выполняться только 1 задача группы A.Они должны быть в очереди.(Необязательно блокировать задачи группы B между выполнением двух задач группы A, если все еще применяются предыдущие условия)

Я считаю, что мой метод работает, но мне не нравитсяЭто работает из-за множества точек синхронизации, которые он использует, и из-за того, что я сплю, ожидая счетчика.В любом случае код будет ниже

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);
}

Если у кого-то есть более хорошее решение, даже если оно будет чуть лучше, это будет здорово

Ответы [ 2 ]

5 голосов
/ 11 марта 2011

Звучит так, как будто вы хотите использовать ReadWriteLock.Пусть каждая задача группы A получает readLock(), а каждая задача группы B - writeLock().

Таким образом, любое количество задач группы A можетзапускаться одновременно, но может выполняться только одна задача группы B (в этот момент другие задачи группы A не могут быть запущены).

ReadWriteLock rwLock = getSharedReadWriteLock();
Lock lock = groupA ? rwLock.readLock() : rwLock.writeLock();
lock.lock();
try {
  return runInBackground(params);
} finally {
  lock.unlock();
}
0 голосов
/ 11 марта 2011

Если у вас есть верхняя граница для числа одновременных задач группы B (даже если она очень большая), вы сможете достичь правил, которые вы описываете, с помощью одного семафора.

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

Задача группы А:

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

Задача группы B:

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

Конечный результат: пока работает любая группа B, A не может получить количество разрешений, которое ей требуется. Как только это произойдет, ни B не сможет получить разрешение, ни один другой не сможет получить A.

...