Снятие блокировки, как только она пройдена - PullRequest
0 голосов
/ 18 июля 2011

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

Я бы хотел избежать запуска сборщика мусора, пока это происходит, и поэтому я избегаю выделения объектов. Таким образом, план состоит в том, что сервер будет ассоциировать один объект параметра с каждым клиентом и всегда будет передавать один и тот же параметр каждый раз, когда клиента просят выполнить работу. Однако это создает проблему, состоящую в том, что параметр должен быть переустановлен на «действительный», и в то же время гарантируется, что клиент (который, возможно, сохранил ссылку на параметр с прошлого раза) не может начать использовать его (скажем в другой ветке) прежде чем его попросят начать делать работу.

Таким образом, все открытые методы параметра синхронизируются, и устанавливается «действительное» состояние, за которым следует (синхронный) beginWork вызов клиента внутри блока synchronized. Но это создает проблему, заключающуюся в том, что клиент неосознанно удерживает блокировку параметра, что может вызвать проблемы, если клиент хочет разделить свою работу на несколько потоков. Поэтому я ввел однопоточный ExecutorService, который сервер использует для отключения вызова на beginWork, что гарантирует, что сервер быстро снимет блокировку. Но мне кажется, что это плохой дизайн - зачем этому классу нужен совсем другой поток?

Итак, мой вопрос: учитывая все, что я только что изложил, я допустил какую-то ужасную ошибку в дизайне, из-за которой я слишком усложнил этот класс, или это действительно должен быть такой комплекс?

interface Client {
    public void doWork(Param p);
}

interface Param {
    public boolean isValid();
}

class Server {
    private final ExecutorService executor = Executors.newSingleThreadExecutor();
    private final MyParam[] params;

    private class MyParam implements Param {
        boolean isValid;
        Client client;
        Runnable task = new Runnable() {
            @Override
            public void run() {
                client.doWork(MyParam.this);
            }
        }

        @Override
        public synchronized boolean isValid() {
            return isValid;
        }
    }

    public void runClients() {
        while (true) {
            for (MyParam param : params) {
                synchronized(param) {
                    param.isValid = true;
                    // fork the client so we release the lock promptly (ugly!)
                    executor.execute(param.task);
                }

                // ... wait for the client to finish ...
            }
        }
    }
}

1 Ответ

0 голосов
/ 21 июля 2011

Я исправил это, добавив явный ReentrantLock к интерфейсу Param.Поэтому вместо использования синхронизированного блока я просто блокирую параметр и позволяю клиенту разблокировать его, если он этого хочет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...