Модераторы: LSD, AntonSaburov

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Организация синхронизированной работы, Допрыгался. 
V
    Опции темы
Platon
Дата 23.1.2008, 12:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 16
Всего: 40



Здравствуйте, уважаемые.

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

Код

public class TestConnection {
    public boolean hasUser(String user) {
        session.write(new HasUserRequest(user));
        return true; // вот тут то надо дождаться ответа
    }
}


ответные сообщения идут от соединений вот так:

Код

public class MessageHandler {
    public void messageReceived(IoSession session, Object message) {

    }
}


Думал сделать так:

Код

public class TestConnection {
    private static final ResponseWaitor<Boolean> waitor = new ResponseWaitor<Boolean>();

    public boolean hasUser(String user) {
        session.write(new HasUserRequest(user));
        return waitor.getObject();
    }

    public void notifyHasUser(boolean hasUser) {
        waitor.setObject(hasUser);
    }
}


Код

public class MessageHandler {
    public void messageReceived(IoSession session, Object message) {
         if (message instanceof HasUserResponse) {
             connectionsManager.getTestConnection(session).notifyHasUser(((HasUserResponse)message).hasUser);
         }
    }
}


Все бы ничего но для каждого синхронизированного запроса так изголяться?! уж тяжело даже мне. Благо пока 1 такой метод, но если поставить на массовый поток клепание синхронизированых методов?

Я явно упустил какой-то легкий подход.


Это сообщение отредактировал(а) Platon - 23.1.2008, 12:03
PM MAIL ICQ   Вверх
Platon
Дата 23.1.2008, 13:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 16
Всего: 40



Кстати вот мой объект, ожидающий ответа:
Код

public class ResponseWaitor<E> {
    private E resp;

    public synchronized void setObject(E resp) {
        this.resp = resp;
        notify();
    }

    public boolean isDone() {
        return resp != null;
    }

    public E getObject() {
        while(!isDone()) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return resp;
    }
}


Но, боюсь, что если более 1 запроса будет ожидать обработки, то могут возникнуть разного рода проблемы?
К примеру, в сокет отправилось 2 запроса о проверке наличия пользователя, и как я вижу, 2 потока лягут спать на объекте ResponseWaitor и при обращении к методу ResponseWaitor.notify() неизвестно какой поток пробудится...
PM MAIL ICQ   Вверх
LSD
Дата 23.1.2008, 14:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Leprechaun Software Developer
****


Профиль
Группа: Модератор
Сообщений: 15718
Регистрация: 24.3.2004
Где: Dublin

Репутация: 210
Всего: 538



Я делал так:
- один поток обрабатывал сеть (отправлял и получал оттуда данные)
- другие потоки вызывали методы этого объекта для отправки данных
- когда метод хотел синхронно отправить сообщение, объект работающий с потоком обработки сети отправлял данные, записывал в что ожидается ответ на сообщение с таким-то ID, и усыплял поток
- когда приходило сообщение, проверял что это подтверждение, будил все потоки и у каждого проверял, что это сообщение для него, нужный поток получал управление обратно и ответ, а все остальные снова засыпали дальше


--------------------
Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it.
PM MAIL WWW   Вверх
AntonSaburov
Дата 23.1.2008, 14:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Штурман
****


Профиль
Группа: Модератор
Сообщений: 5658
Регистрация: 2.7.2002
Где: Санкт-Петербург

Репутация: 51
Всего: 118



Что-то ты и правда намудрил. Попробуй описать задачу целиком - может найдется просто иное решение. Проще и "стандартнее".
PM MAIL WWW ICQ   Вверх
Platon
Дата 23.1.2008, 14:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 16
Всего: 40



LSD, ну на самом деле не намного проще получается :( или я просто не понял.


AntonSaburov, использую библиотеку Apache MINA для организации сети.
Задача: оформить синхронизированную работу функций.
Вот я накидал как оно выглядит
Клиентская часть
user posted image

Серверная часть
user posted image

Главная загвоздка находится в классе ServerConnection, как раз там необходимо усыплять потоки.
PM MAIL ICQ   Вверх
LSD
Дата 23.1.2008, 15:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Leprechaun Software Developer
****


Профиль
Группа: Модератор
Сообщений: 15718
Регистрация: 24.3.2004
Где: Dublin

Репутация: 210
Всего: 538



Цитата(Platon @  23.1.2008,  14:59 Найти цитируемый пост)
ну на самом деле не намного проще получается :( или я просто не понял

Вообщем да. В любом случае проблема состоит в том, что надо усыплять поток до тех пор пока не придёт ответ. Хотя тут код получится не такой уж чтобы сверх сложный.


--------------------
Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it.
PM MAIL WWW   Вверх
Platon
Дата 23.1.2008, 16:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 16
Всего: 40



Хм, странно, попробовал потестировать со своим ResponseWaitor'ом тест прошел, глюков и дедлоков не было... надо думать что всё таки так дело нормально пройдет, проверим еще на нескольких тачках.
PM MAIL ICQ   Вверх
COVD
Дата 23.1.2008, 17:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 17
Всего: 43



Цитата

К примеру, в сокет отправилось 2 запроса 


Очевидно, вы хотите синхронные запросы пропускать через один канал связи, т.е. через один сокет. Это неестественно. Натурально будет, если для синхронного запроса открыть новое соединение, получить ответ и закрыть соединение. Используя асинхронный канал для синхронных запросов вы получаете свои трудности:
 - иметь коллекцию, где потоки запросов будут ожидать ответа, 
 - иметь таймер, который мониторит коллекцию и выбрасывает потоки, у которых задержка ответа превышает таймаут, 
 - в каждом запросе отправлять уникальный ID запроса
 - в каждом ответе на запрос возвращать ID запроса, чтобы отыскать поток в коллекции и разбудить его.  
PM MAIL   Вверх
Platon
Дата 23.1.2008, 17:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 16
Всего: 40



Цитата(COVD @  23.1.2008,  18:39 Найти цитируемый пост)
Натурально будет, если для синхронного запроса открыть новое соединение, получить ответ и закрыть соединение.

Ну, уж так уж натурально?
видимо с ID придется бегать...
PM MAIL ICQ   Вверх
LSD
Дата 23.1.2008, 17:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Leprechaun Software Developer
****


Профиль
Группа: Модератор
Сообщений: 15718
Регистрация: 24.3.2004
Где: Dublin

Репутация: 210
Всего: 538



Ты главное потоков побольше запусти, и дольше тестируй.

P.S. У меня там ещё тайм аут обрабатывался. А у тебя как с этим? 


--------------------
Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it.
PM MAIL WWW   Вверх
Platon
Дата 23.1.2008, 17:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 16
Всего: 40



На самом деле никак. Я еще вечерком подумаю над тем что мне насоветовали ^_^
PM MAIL ICQ   Вверх
COVD
Дата 23.1.2008, 18:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 17
Всего: 43



Цитата

Ну, уж так уж натурально?


именно так, потому что не надо синхронную схему приспосабливать к асинхронному каналу связи - никаких ID, коллекций, таймеров и блоков синхронизаций.  
PM MAIL   Вверх
Platon
Дата 23.1.2008, 18:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 16
Всего: 40



COVD, это уже получается сервис? но это соединение также обслуживает асинхронные запросы.

В моем примере на самом деле проблема только с тем кто разбудится. Но 100% Гарантировано, что при записи в поток запросов ответы придут в той же (ненарушенной) последовательности.
PM MAIL ICQ   Вверх
COVD
Дата 23.1.2008, 18:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 17
Всего: 43



Цитата

COVD, это уже получается сервис?

фактически, да. Если сиюминутная проблема только в том, "кто разбудится", то кладите потоки (т.е. обьекты, на которых они спят) в ArrayList и в том же порядке извлекайте и будите. 

Это сообщение отредактировал(а) COVD - 23.1.2008, 18:56
PM MAIL   Вверх
Platon
Дата 23.1.2008, 19:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 16
Всего: 40



Ок, логичное решение... не догадался.
НО, вот будет утомительно плясать вокруг каждого такого метода...

Каков же опыт RMI, на сколько я знаю там все методы сделаны в синхронном стиле. но нам плясать никак не надо. Может быть этот опыт можно повзаимствовать или придется все методы делать синхронными.
PM MAIL ICQ   Вверх
Platon
Дата 24.1.2008, 11:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 16
Всего: 40



Свелось всё к классической задачке ^_^

Код

public class ResponseWaitor<E> {

    private LinkedList<E> queue = new LinkedList<E>();
    private final Object lock = new Object();
    public void add(E obj) {
        synchronized(lock) {
            queue.add(obj);
            lock.notify();
        }
    }
    
    public E get() {
        synchronized(lock) {
            while (queue.isEmpty()) {
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    return null;
                }
            }
            return queue.removeFirst();
        }
        
    }
}


Это сообщение отредактировал(а) Platon - 24.1.2008, 11:40
PM MAIL ICQ   Вверх
Platon
Дата 24.1.2008, 11:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 16
Всего: 40



И получается не так уж и страшно:

Код

private ResponseWaitor<Boolean> waitor; 

    public boolean addUserToContacts(String sn, String sn1) {
        connection.write(new AddUserRequest(sn, sn1));
        return waitor.get();

    }

    void userAdded(boolean added) {
        waitor.add(added);
    }

PM MAIL ICQ   Вверх
Platon
Дата 26.1.2008, 15:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 16
Всего: 40



Нет, вариант оказался неправильным, вот новый, но я даже не рискнул его запустить, просто не укладывается в мозгу как сделать правильно.
Опытные тредеры!!! Нужна консультация.

Код

public class ResponseWaitor<E> {

    private final LinkedList<E> queue = new LinkedList<E>();
    private final LinkedList monitors = new LinkedList();

    public synchronized void add(E obj) {
        Object o;
        synchronized(monitors) {
            while (monitors.isEmpty()) {
                try {
                    monitors.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            o = monitors.removeFirst();
        }
        synchronized(queue) {
            queue.add(obj);
        }
        synchronized(o) {
            o.notify();
        }
    }

    public E get() {
        Object o;
        synchronized(monitors) {
            o = new Object();
            monitors.add(o);
            monitors.notify();
        }

        synchronized(queue) {
            while (queue.isEmpty()) {
                synchronized(o) {
                try {
                    o.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                }
            }
            return queue.removeFirst();
        }
    }
}


Добавлено через 6 минут и 47 секунд
Хм, нет, этот вариант конечно же завален.
PM MAIL ICQ   Вверх
Platon
Дата 26.1.2008, 15:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 16
Всего: 40



Вот кажется валидный пример:

Код

public class ResponseWaitor<E> {

    private LinkedList<E> queue = new LinkedList<E>();
    private LinkedList monitors = new LinkedList();
    private final Object lock = new Object();
    public void add(E obj) {
        Object o;
        synchronized(lock) {
            while (monitors.isEmpty()) {
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            queue.add(obj);
            o = monitors.removeFirst();
        }

        synchronized(o) {
            o.notify();
        }
    }

    public E get() {
        Object o = new Object();
        synchronized(lock) {
            monitors.add(o);
            lock.notify();
        }
        synchronized(o) {
            while (queue.isEmpty()) {
                try {
                    o.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return queue.removeFirst();
        }
    }
}

PM MAIL ICQ   Вверх
Prol
Дата 26.1.2008, 20:51 (ссылка)    | (голосов:3) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 125
Регистрация: 11.1.2008
Где: Кыев, Украина

Репутация: нет
Всего: нет



Цитата(LSD @ 23.1.2008,  15:41)
В любом случае проблема состоит в том, что надо усыплять поток до тех пор пока не придёт ответ. 

Усыплять поток - это всё равно что хальтовать процессор в ожидании немаскируемого прерывания :о))) Моветон :о) 
Да посади проц в фарева цикл на обработку задач :о)
PM MAIL WWW ICQ   Вверх
ivg
Дата 26.1.2008, 21:54 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Autonomous R&D
**


Профиль
Группа: Участник
Сообщений: 686
Регистрация: 8.2.2006
Где: Екатеринбург

Репутация: 33
Всего: 81



Цитата(Prol @  26.1.2008,  20:51 Найти цитируемый пост)
Усыплять поток - это всё равно что хальтовать процессор в ожидании немаскируемого прерывания :о))) Моветон :о) 
Да посади проц в фарева цикл на обработку задач :о)

Мыслить в контексте однозадачности - вот моветон.  smile 
Вобщем, rtfm, как говорится.
PM MAIL   Вверх
Platon
Дата 26.1.2008, 22:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 16
Всего: 40



Prol, от куда такие сведения? лупить в бесконечном цикле обработку задачи, которые поступают через неопределенные промежутки времени. Это убийство процессорного времени воистину!
PM MAIL ICQ   Вверх
Prol
Дата 26.1.2008, 23:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 125
Регистрация: 11.1.2008
Где: Кыев, Украина

Репутация: нет
Всего: нет



Цитата(Platon @ 26.1.2008,  22:27)
Prol, от куда такие сведения? лупить в бесконечном цикле обработку задачи, которые поступают через неопределенные промежутки времени. Это убийство процессорного времени воистину!

Процессор должен работать, а человек - думать :о)

Не слипайте потоки, дайте им работу :о)
Если вы слипаете поток, значит он не нужен в вашей проге :о)
Зачем заводить поток, который вы же сами и останавливаете?

Вот классно сделано в транспьютерах: есть очередь процессоров, есть очередь задач,  свободный процессор отдаётся ожидающей задаче :о) Если процессорам нечего делать, значит все задачи выполнены :о)

PM MAIL WWW ICQ   Вверх
LSD
Дата 27.1.2008, 04:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Leprechaun Software Developer
****


Профиль
Группа: Модератор
Сообщений: 15718
Регистрация: 24.3.2004
Где: Dublin

Репутация: 210
Всего: 538



Цитата(Prol @  26.1.2008,  20:51 Найти цитируемый пост)
Усыплять поток - это всё равно что хальтовать процессор в ожидании немаскируемого прерывания :о))) Моветон :о) 
Да посади проц в фарева цикл на обработку задач :о) 

Полная чушь!
1. Приостанавливать поток, и выполнять halt у процессора - это две большие разницы.
2. Если задача предполагает ожидание некого события, то поток должен заснуть, а не молотить никому не нужный цикл напрасно загружая процессор.

Добавлено через 46 секунд
Цитата(Prol @  26.1.2008,  23:24 Найти цитируемый пост)
Не слипайте потоки, дайте им работу :о)
Если вы слипаете поток, значит он не нужен в вашей проге :о)
Зачем заводить поток, который вы же сами и останавливаете?

Ты не понимаешь разницы между остановкой и приостановкой?


--------------------
Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it.
PM MAIL WWW   Вверх
Prol
Дата 27.1.2008, 11:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 125
Регистрация: 11.1.2008
Где: Кыев, Украина

Репутация: нет
Всего: нет



Цитата(LSD @ 27.1.2008,  04:16)
2. Если задача предполагает ожидание некого события, то поток должен заснуть

А какое отношение поток имеет к задаче? Это два разных объекта :о) Если задаче нужно чего-то ожидать, то причём тут поток? Поток передаётся другой задаче :о)
PM MAIL WWW ICQ   Вверх
LSD
Дата 27.1.2008, 13:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Leprechaun Software Developer
****


Профиль
Группа: Модератор
Сообщений: 15718
Регистрация: 24.3.2004
Где: Dublin

Репутация: 210
Всего: 538



Цитата(Prol @  27.1.2008,  11:30 Найти цитируемый пост)
А какое отношение поток имеет к задаче? Это два разных объекта :о) Если задаче нужно чего-то ожидать, то причём тут поток? Поток передаётся другой задаче :о) 

Тяжкое наследие DOS-а, сами распределяем память, сами организуем многозадачность smile 

Во первых попробуй реализовать такой механизм, и посмотрим что у тебя получится smile 
Во вторых, что ты будешь делать если нужные данные поступили и пора возвращать управление первой задаче, а вторая задача которая заняла поток, еще и не думает заверщаться, или хуже того блокирована на IO-операции?


--------------------
Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it.
PM MAIL WWW   Вверх
Prol
Дата 27.1.2008, 16:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 125
Регистрация: 11.1.2008
Где: Кыев, Украина

Репутация: нет
Всего: нет



Цитата(LSD @ 27.1.2008,  13:39)
Цитата(Prol @  27.1.2008,  11:30 Найти цитируемый пост)
А какое отношение поток имеет к задаче? Это два разных объекта :о) Если задаче нужно чего-то ожидать, то причём тут поток? Поток передаётся другой задаче :о) 


Во первых попробуй реализовать такой механизм, и посмотрим что у тебя получится smile 
Во вторых, что ты будешь делать если нужные данные поступили и пора возвращать управление первой задаче, а вторая задача которая заняла поток, еще и не думает заверщаться, или хуже того блокирована на IO-операции?

Нет необходимости писать свое

Даг Ли создал отличную открытую библиотеку утилит параллельности, util.concurrent, которая включает объекты-мьютексы, семафоры, коллекции, такие как очереди и хэш-таблицы, хорошо работающие при параллельном доступе, и несколько реализаций рабочей очереди. Класс PooledExecutor из этого пакета - эффективная, широко использующаяся, правильная реализация пула потоков, основанного на рабочей очереди. Прежде чем пытаться писать собственное программное обеспечение, которое вполне может оказаться неправильным, вы можете рассмотреть использование некоторых утилит в util.concurrent. Библиотека util.concurrent включена в Java Development Kit 1.5.

Вот хороший учебник для овладения с практическими примерами.
http://gee.cs.oswego.edu/dl/classes/EDU/os...rent/intro.html




Это сообщение отредактировал(а) Prol - 27.1.2008, 16:49
PM MAIL WWW ICQ   Вверх
Platon
Дата 27.1.2008, 17:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 16
Всего: 40



В этом вопросе я уже не компетентен...

Добавлено через 9 минут и 33 секунды
хммм, в тамом случае, хотелось бы увидеть от Prol решения моей проблемы с помощью стандартного пакета Java, из этого я думаю, сможет получиться хорошая статья.

Это сообщение отредактировал(а) Platon - 27.1.2008, 17:25
PM MAIL ICQ   Вверх
LSD
Дата 28.1.2008, 13:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Leprechaun Software Developer
****


Профиль
Группа: Модератор
Сообщений: 15718
Регистрация: 24.3.2004
Где: Dublin

Репутация: 210
Всего: 538



Цитата(Prol @  27.1.2008,  16:48 Найти цитируемый пост)
Даг Ли создал отличную открытую библиотеку утилит параллельности, util.concurrent, которая включает объекты-мьютексы, семафоры, коллекции, такие как очереди и хэш-таблицы, хорошо работающие при параллельном доступе, и несколько реализаций рабочей очереди. Класс PooledExecutor из этого пакета - эффективная, широко использующаяся, правильная реализация пула потоков, основанного на рабочей очереди. Прежде чем пытаться писать собственное программное обеспечение, которое вполне может оказаться неправильным, вы можете рассмотреть использование некоторых утилит в util.concurrent.

Из java.util.concurrent в данном случае, я вижу применимость только для Lock/Condition. Каким образом ты предлагаешь использовать PooledExecutor для данной задачи?


--------------------
Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it.
PM MAIL WWW   Вверх
COVD
Дата 28.1.2008, 19:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 17
Всего: 43



Не морочьте голову  smile .  В java есть только потоки (threads). В приложении может быть запущено много потоков. Потокам выделяется память и периодически порция процессорного времени в зависимости от приоритета потока. Если для выполнения действий в потоке требуется дождаться некоторого события, то поток переводится в состояние ожидания и свою порцию процессорного времени использовать не будет.
Prol, java потоки - это воплощение вашей идеи с независимыми приложениями, использующими общую память. Можете гордиться  smile .  

Это сообщение отредактировал(а) COVD - 28.1.2008, 19:32
PM MAIL   Вверх
Prol
Дата 28.1.2008, 23:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 125
Регистрация: 11.1.2008
Где: Кыев, Украина

Репутация: нет
Всего: нет



Цитата(COVD @ 28.1.2008,  19:29)
Prol, java потоки - это воплощение вашей идеи с независимыми приложениями, использующими общую память. 

К сожалению все они рухнут, если произойдёт operation exeption, access violation или overflow в самой JVM.
PM MAIL WWW ICQ   Вверх
COVD
Дата 28.1.2008, 23:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 17
Всего: 43



Ничто не вечно. 
PM MAIL   Вверх
Platon
Дата 19.2.2008, 19:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 16
Всего: 40



Dear Lord, help me!!!

Я до сих пор не могу найти решения. Мое последнее решение также впадает в ступор:

Код

package platon.network;

import java.util.LinkedList;

public class ResponseWaitor1<E> {
    private final LinkedList<Flag> monitors = new LinkedList<Flag>();
    private final LinkedList<E> queue = new LinkedList<E>();

    public void add(E obj) {
        Flag o;
        synchronized(monitors) {
            while (monitors.isEmpty()) {
                try {
                    System.out.println(Thread.currentThread().getId() + " Waiting monitors");
                    monitors.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            o = monitors.removeFirst();
        }
        System.out.println(Thread.currentThread().getId() + " Monitor passed");
        o.done();
        System.out.println(Thread.currentThread().getId() + " Flag got");
        synchronized(queue) {
            queue.add(obj);
            System.out.println(Thread.currentThread().getId() + " Queue notify");
            queue.notify();
        }
    }

    public E get() {
        Flag o = new Flag();
        synchronized(monitors) {
            monitors.add(o);
            System.out.println(Thread.currentThread().getId() + " Monitor notify");
            monitors.notify();
        }

        while (!o.isDone()) {
            synchronized(o) {
                try {
                    System.out.println(Thread.currentThread().getId() + " Waiting flag");
                    o.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println(Thread.currentThread().getId() + " Flag passed");

        synchronized(queue) {
            while (queue.isEmpty()) {
                try {
                    System.out.println(Thread.currentThread().getId() + " Waiting queue");
                    queue.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getId() + " queue passed");
            return queue.removeFirst();
        }
    }

    public static void main(String[] args) {
        final ResponseWaitor1<Integer> waitor = new ResponseWaitor1<Integer>();



        new Thread(new Runnable() {
            int i;
            public void run() {
                for (int i = 0; i < 2000; i++) {
                    System.out.println(Thread.currentThread().getId() + " " + waitor.get());
                }
            }
        }).start();

        new Thread(new Runnable() {
            int i;
            public void run() {
                for (int i = 0; i < 2000; i++) {
                    System.out.println(Thread.currentThread().getId() + " " + waitor.get());
                }
            }
        }).start();

        new Thread(new Runnable() {
            int i;
            public void run() {
                for (int i = 0; i < 4000; i++) {
                    waitor.add(i);
                }
            }
        }).start();
    }
}



Добавлено @ 19:11
Я не уверен как правильно называется класс Flag, возможно это некий семафор.

Это сообщение отредактировал(а) Platon - 20.2.2008, 13:12
PM MAIL ICQ   Вверх
SoulKeeper
Дата 19.2.2008, 22:40 (ссылка)    | (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 375
Регистрация: 14.1.2007
Где: Ukraine, Lviv.

Репутация: 11
Всего: 15



Я конечно понимаю что изобретение своего велосипеда делает программиста более квалифицированым, но есть

1). RMI. Правда кажись работает на блокирующем I/O, в дебри не влезаю, да и для моих потребностей, обслуживание от силы 15 клиентов, мне nio не особо и нужно.
2). JERI в Jini. В свое время обращал внимание, но в глубь копать не стал, т.к. вариант #1 подошел вполне. Кажись есть возможность использование nio.

Собственно вот такие вот дела smile
PM MAIL   Вверх
Platon
Дата 20.2.2008, 10:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 16
Всего: 40



Зачем мне ваши технологии, когда я могу без них обойтись. Я с удовольствием перейму стандартное решение текущей задачи, но технологии мне советовать не надо.
PM MAIL ICQ   Вверх
SoulKeeper
Дата 20.2.2008, 11:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 375
Регистрация: 14.1.2007
Где: Ukraine, Lviv.

Репутация: 11
Всего: 15



Вообще-то это и есть стандартные решения текущей задачи.

Это сообщение отредактировал(а) SoulKeeper - 20.2.2008, 11:07
PM MAIL   Вверх
Platon
Дата 20.2.2008, 11:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 16
Всего: 40



задача сводится лишь к тому чтобы из асинхронной работы была возможность запросить и дождаться ответа от общего объекта, причем в пределах одной JVM. Спрашивается зачем мне RMI???

Это сообщение отредактировал(а) Platon - 20.2.2008, 11:30
PM MAIL ICQ   Вверх
Platon
Дата 20.2.2008, 13:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 16
Всего: 40



Последнее из выведенного на экран оказывается всегда похожим на

Код

11 Monitor passed
11 Flag got
11 Queue notify
11 Waiting monitors
10 Waiting flag


Всегда заканчивается ожиданием готовности флажка. и почему то в этот момент он не срабатывает :( хотя во 2-й строчке он уже был выброшен.

PM MAIL ICQ   Вверх
Platon
Дата 22.2.2008, 13:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 16
Всего: 40



Вот оно!!! Как говорится: "Эврика"!!!

Код

public class ResponseWaitor1<E> {
    private final LinkedList<Flag> monitors = new LinkedList<Flag>();
    private final LinkedList<E> queue = new LinkedList<E>();

    public void add(E obj) {
        Flag o;
        synchronized(monitors) {
            while (monitors.isEmpty()) {
                try {
                    //System.out.println(Thread.currentThread().getId() + " Waiting monitors");
                    monitors.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            o = monitors.removeFirst();
        }
        //System.out.println(Thread.currentThread().getId() + " Monitor passed");
        o.done();
        //System.out.println(Thread.currentThread().getId() + " Flag got");
        synchronized(queue) {
            queue.add(obj);
            //System.out.println(Thread.currentThread().getId() + " Queue notify");
            queue.notify();
        }
    }

    public E get() {
        Flag o = new Flag();
        synchronized(monitors) {
            monitors.add(o);
            //System.out.println(Thread.currentThread().getId() + " Monitor notify");
            monitors.notify();
        }

        synchronized(o) {
            while (!o.isDone()) {
                try {
                    //System.out.println(Thread.currentThread().getId() + " Waiting flag" + o.isDone());
                    o.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        //System.out.println(Thread.currentThread().getId() + " Flag passed");

        synchronized(queue) {
            while (queue.isEmpty()) {
                try {
                    //System.out.println(Thread.currentThread().getId() + " Waiting queue");
                    queue.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //System.out.println(Thread.currentThread().getId() + " queue passed");
            return queue.removeFirst();
        }
    }

    public static void main(String[] args) {
        final ResponseWaitor1<Integer> waitor = new ResponseWaitor1<Integer>();

        new Thread(new Runnable() {
            int i;
            public void run() {
                for (int i = 0; i < 40000; i++) {
                    waitor.add(i);
                }
            }
        }).start();

        new Thread(new Runnable() {
            int i;
            public void run() {
                for (int i = 0; i < 20000; i++) {
                    System.out.println(Thread.currentThread().getId() + " " + waitor.get());
                }
            }
        }).start();

        new Thread(new Runnable() {
            int i;
            public void run() {
                for (int i = 0; i < 20000; i++) {
                    System.out.println(Thread.currentThread().getId() + " " + waitor.get());
                }
            }
        }).start();
    }
}


Жаль, что мне никто не помог, и столько времени пришлось ломать голову над этим пустячком.
Проблема оказалась вот в этом куске:

Код

 while (!o.isDone()) {
            synchronized(o) {
                try {
                    System.out.println(Thread.currentThread().getId() + " Waiting flag");
                    o.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }


Поменял на 

Код

synchronized(o) {
            while (!o.isDone()) {
                try {
                    //System.out.println(Thread.currentThread().getId() + " Waiting flag" + o.isDone());
                    o.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }


Добавлено через 10 минут
Я бы сам себе за такие мучения орден вручил бы!

Это сообщение отредактировал(а) Platon - 22.2.2008, 13:28
PM MAIL ICQ   Вверх
COVD
Дата 22.2.2008, 16:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 17
Всего: 43



Очень удобен для таких задач класс java.util.concurrent.LinkedBlockingQueue - никаких wait и synchronized не нужно. Единственное неудобство - эта очередь не принимает на входе null. Поэтому конец очереди , если есть в нем необходимость, можно определить только поставив в очередь специальный обьект и ловить его на выходе через instanceof  .
PM MAIL   Вверх
Platon
Дата 22.2.2008, 16:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 16
Всего: 40



COVD, дорогой, где ж вы неделю назад были???!!!
PM MAIL ICQ   Вверх
COVD
Дата 22.2.2008, 17:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 17
Всего: 43



Я просто не сразу понял, с чем вы сражались.  smile 

Еще мне кажется, вы не предусмотрели таймаут на ожидание ответа. Ответ ведь может никогда и не придти. А в LinkedBlockingQueue  его можно поставить и тогда, если время ожидания ответа превысит таймаут, очередь выбросит null (поэтому null и запрещен на входе).

Это сообщение отредактировал(а) COVD - 22.2.2008, 17:50
PM MAIL   Вверх
Platon
Дата 22.2.2008, 18:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 16
Всего: 40



Смотрим сюда.
Код

public class ResponseWaitor1<E> {
    private LinkedBlockingQueue<E> queue = new LinkedBlockingQueue<E>();

    public void add(E obj) {
        queue.add(obj);
    }

    public E get() {
        return queue.poll();
    }

    public static void main(String[] args) {
        final ResponseWaitor1<Integer> waitor = new ResponseWaitor1<Integer>();

        new Thread(new Runnable() {
            int i;
            public void run() {
                for (int i = 0; i < 40000; i++) {
                    waitor.add(i);
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {

                }
                System.out.println("There are " + waitor.queue.size() + " items left in queue");
            }
        }).start();

        new Thread(new Runnable() {
            int i;
            public void run() {
                for (int i = 0; i < 20000; i++) {
                    System.out.println(Thread.currentThread().getId() + " " + waitor.get());
                }
            }
        }).start();

        new Thread(new Runnable() {
            int i;
            public void run() {
                for (int i = 0; i < 20000; i++) {
                    System.out.println(Thread.currentThread().getId() + " " + waitor.get());
                }
            }
        }).start();

        
    }
}


Теперь смотрим на конец вывода в консоль:

Цитата

10 39988
10 39989
10 39990
10 39991
10 39992
There are 7 items left in queue

проблемка возникла... судя по всему, в некоторые некоторые моменты poll() выдают одинаковый результат 2-м потокам.
PM MAIL ICQ   Вверх
COVD
Дата 22.2.2008, 18:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 17
Всего: 43



у меня ваш код нормально сработал - последнее выведенное число 39999. А надпись "There are .." выскакивает где-то в середине вывода на консоль, т.е. это еще не конец работы программы.

Это сообщение отредактировал(а) COVD - 22.2.2008, 18:36
PM MAIL   Вверх
Platon
Дата 22.2.2008, 18:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 16
Всего: 40



не-не, надо несколько раз прогу запустить + если где-то в середине, увеличьте задержку до 10 секунд.
PM MAIL ICQ   Вверх
COVD
Дата 22.2.2008, 19:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1655
Регистрация: 26.7.2005

Репутация: 17
Всего: 43



зачем вообще эта задержка? поток, который кладет данные в очередь, может закончить свою работу в любое время. независимо от читающих
PM MAIL   Вверх
Platon
Дата 22.2.2008, 19:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 16
Всего: 40



Ок, код некомпетентный, вот новый:

Код

public class ResponseWaitor1<E> {
    private LinkedBlockingQueue<E> queue = new LinkedBlockingQueue<E>();

    public void add(E obj) {
        queue.add(obj);
    }

    public E get() {
        return queue.poll();
    }

    public static void main(String[] args) throws InterruptedException {
        final ResponseWaitor1<Integer> waitor = new ResponseWaitor1<Integer>();

        Thread t1 = new Thread(new Runnable() {
            int i;
            public void run() {
                for (int i = 0; i < 40000; i++) {
                    waitor.add(i);
                }
            }
        });
        t1.start();

        Thread t2 = new Thread(new Runnable() {
            int i;
            public void run() {
                for (int i = 0; i < 20000; i++) {
                    System.out.println(Thread.currentThread().getId() + " " + waitor.get());
                }
            }
        });
        t2.start();

        Thread t3 = new Thread(new Runnable() {
            int i;
            public void run() {
                for (int i = 0; i < 20000; i++) {
                    System.out.println(Thread.currentThread().getId() + " " + waitor.get());
                }
            }
        });
        t3.start();
        t1.join();
        t2.join();
        t3.join();
        System.out.println("There are " + waitor.queue.size() + " items left in queue");
    }
}


Добавлено через 2 минуты и 50 секунд
Если что, сразу скажу, пробовал add/get делать синхронизированными.
PM MAIL ICQ   Вверх
Platon
Дата 25.2.2008, 13:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1801
Регистрация: 25.4.2006

Репутация: 16
Всего: 40



Вот и подошла к концу моя эпопея. Спасибо COVD за отличную подсказку, работа моего примера была неправильной из-за метода poll() который не ждет появления объекта в очереди, а сразу выбрасывает null.
Правильным решением здесь будет take() Он точно ждет.
PM MAIL ICQ   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
javastic
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1370 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.