Синхронизированные функции в Java - PullRequest
0 голосов
/ 25 ноября 2011

У меня есть класс с функцией, которая синхронизируется примерно так:

public synchronized void enqueue(int number) {...}

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

Можно ли это сделать без с использованием библиотеки Java.util.concurency и только с использованием примитивов синхронизации?

Ограничение не использовать параллелизм не является обязательным

Ответы [ 5 ]

3 голосов
/ 25 ноября 2011

Мне нравится решение AtomicInteger, но, конечно, AtomicInteger является частью пакета параллелизма.Вы можете следовать тому же принципу (но с меньшей эффективностью) с помощью следующего простого кода:

private boolean locked = false;

public void enqueue(int number) {
    synchronized (this) {
        if (locked) {
            return;
        }
        locked = true;
    }

    try {
        // Synchronized goodness goes here.
    } finally {
        synchronized (this) {
            locked = false;
        }
    }
}
0 голосов
/ 25 ноября 2011

Может быть, вы можете синхронизировать объект, который обрабатывает очередь.Если кто-то еще использует очередь, очередь ничего не делает.У меня есть пример, который компилируется и запускается.Очень простой пример, но не симпатичный:

    class Queue {
        public void enqueue(int number) {
            // something in this method for demo purposes only 
            try {
                Thread.sleep(100);
            } catch (InterruptedException e){}
            System.out.println(Thread.currentThread().getName()+" done");
        }
    }

    class Demo {
        private static Queue e = new Queue();

        public void enqueue(int number) {
            Queue q = getQueue();
            if (q!=null) {
                q.enqueue(number);
                releaseQueue(q);
            } else {
                // do nothing since the queue is being used
                System.out.println(Thread.currentThread().getName()+" done doing nothing");
            }
        }

        public synchronized Queue getQueue() {
            Queue b = e;
            e = null;
            return b;
        }

        public synchronized void releaseQueue(Queue q) {
            e = q;
        }

        public static void main(String[] args) {
            for (int j = 0; j < 5; j++) {
                Thread t = new Thread(new Runnable() {
                    public void run() {
                        Demo d = new Demo();
                        d.enqueue(5);
                    }
                }, "Thread "+j);
                t.start();
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e){}
            }
        }

    }
0 голосов
/ 25 ноября 2011

Вместо использования каких-либо примитивов синхронизации я бы порекомендовал использовать что-то вроде класса AtomicInteger для использования операции CAS (сравнение и замена) для вашей стратегии анти-параллелизма:

public void enqueue(int number) {
    if (!atomicInteger.compareAndSet(0, 1) {
        return;
    }

    try {
        // Synchronized goodness goes here.
    } finally {
        atomicInteger.set(0);
    }
}
0 голосов
/ 25 ноября 2011

Поскольку вы ограничены здесь, вот что я бы сделал:

Создайте класс с возможностью сообщить ему, что вы хотите заблокировать его.Существует два типа блокировок: пассивная блокировка и активная блокировка.Пассивная блокировка позволит пропускать неограниченное количество потоков.Активная блокировка сделает его принадлежащим только этому потоку.

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

Когда вы хотите активную блокировку, вы ждете, пока все текущие пассивные блокировки не будут зарегистрированы.Если в настоящее время есть активная блокировка (сохраните ссылку на поток, чтобы узнать, есть ли она, используя Thread.currentThread()), тогда дождитесь уведомления.Затем вы можете установить себя в качестве упомянутой темы.Когда вы отменяете регистрацию, если ожидают активные блокировки, сообщите об этом одной из них (рассмотрите Set<Thread>, чтобы зарегистрировать это).Если нет, сообщите обо всех пассивных блокировках, которые ждут, и они могут пройти.

Здесь будет много вопросов без ответа, и я сомневаюсь, что это идеально, но это большая часть того, что выищем ...

0 голосов
/ 25 ноября 2011

ДА Вы можете реализовать блокировку самостоятельно, управляя статической переменной в этом классе или используя, например, текстовый файл «lock».

ОДНАКО Хотя этот упрощенный взлом не будет ужасно сложным - пакетное решение java.util.concurrency будет ДАЖЕ ПРОСТО, И это лучший выбор, потому что, как вы быстро найдете, при сборке многопоточные ресурсы в приложения, наши потребности быстро превзойдут ваши текущие ожидания

Не беспокойтесь о пакете ВСЕГО параллелизма - я обнаружил, что для изучения простой и многопоточной логики с минимальными усилиями может потребоваться всего лишь 3 минуты, чтобы научиться использовать поля AtomicBoolean или AtomicLong.

...