Замените связанный список блокирующей очередью для параллелизма - PullRequest
0 голосов
/ 06 октября 2019

Я реализовал решение для https://www.programcreek.com/2014/08/leetcode-design-phone-directory-java/, как показано в листинге 1 ниже:

class PhoneDirectory {
    private final LinkedList<Integer> q;
    private final boolean[] used;

    public PhoneDirectory(int maxNumbers) {
        q = new LinkedList<>();
        used = new boolean[maxNumbers];
        for (int i = 0; i < maxNumbers; i++) {
            q.offer(i);
        }
    }

    public int get() {
        if (!q.isEmpty()) {
            int num = q.poll();
            used[num] = true;
            return num;
        }
        return -1;
    }

    public void release(int number) {
        if (used[number]) {
            used[number] = false;
            q.offer(number);
        }
    }
}

Однако указанное решение является однопоточным и завершится ошибкой, если несколько потоков одновременно получат доступ к объекту PhoneDirectory.

Итак, я реализовал поточно-ориентированную версию в листинге 2 ниже, с немного другой логикой:

public class PhoneDirectory {

    private int curr;
    private final int[] next;
    private final Object lock = new Object();
    private final long SLEEP = 2000;

    public PhoneDirectory(int size) {
        next = new int[size];
        curr = 0;
        for (int i = 0; i < size; i++) {
            next[i] = (i + 1) % size;
        }
    }

    public int get(final long sleepInSeconds) throws InterruptedException {
        synchronized (lock) {
            final long sleepInMills = sleepInSeconds * 1000;
            long startTime = System.currentTimeMillis();
            try {
                while (next[curr] == -1) {
                    if (System.currentTimeMillis() - startTime >= sleepInMills) {
                        return -1;
                    }
                    lock.wait(SLEEP);
                }
                int res = curr;
                curr = next[curr];
                next[res] = -1;
                return res;
            } finally {
                lock.notify();
            }
        }
    }

    public void release(int number) {
        synchronized (lock) {
            try {
                if (next[number] != -1) {
                    return;
                }
                next[number] = curr;
                curr = number;
            } finally {
                lock.notify();
            }
        }
    }
}
  1. Действительно ли листинг 2 действительно поточно-ориентирован? И это правильный способ реализации поточно-безопасного кода?
  2. Может ли он масштабироваться, например, если есть сотни потоков и миллионы чисел?
  3. Могу ли я просто заменить LinkedList на LinkedBlockingQueue (влистинг 1) и ожидать, что он будет потокобезопасным? Будет ли это лучше, чем перечисление 2 выше?
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...