| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Java: Общие вопросы > Организация синхронизированной работы |
| Автор: Platon 23.1.2008, 12:01 | ||||||||
| Здравствуйте, уважаемые. У меня тут щепетильная ситуация... Сначала искал возможности для асинхронной работы с удаленными компами, нашел, а теперь не могу сделать синхронную работу...
ответные сообщения идут от соединений вот так:
Думал сделать так:
Все бы ничего но для каждого синхронизированного запроса так изголяться?! уж тяжело даже мне. Благо пока 1 такой метод, но если поставить на массовый поток клепание синхронизированых методов? Я явно упустил какой-то легкий подход. |
| Автор: Platon 23.1.2008, 13:45 | ||
Кстати вот мой объект, ожидающий ответа:
Но, боюсь, что если более 1 запроса будет ожидать обработки, то могут возникнуть разного рода проблемы? К примеру, в сокет отправилось 2 запроса о проверке наличия пользователя, и как я вижу, 2 потока лягут спать на объекте ResponseWaitor и при обращении к методу ResponseWaitor.notify() неизвестно какой поток пробудится... |
| Автор: LSD 23.1.2008, 14:11 |
| Я делал так: - один поток обрабатывал сеть (отправлял и получал оттуда данные) - другие потоки вызывали методы этого объекта для отправки данных - когда метод хотел синхронно отправить сообщение, объект работающий с потоком обработки сети отправлял данные, записывал в что ожидается ответ на сообщение с таким-то ID, и усыплял поток - когда приходило сообщение, проверял что это подтверждение, будил все потоки и у каждого проверял, что это сообщение для него, нужный поток получал управление обратно и ответ, а все остальные снова засыпали дальше |
| Автор: AntonSaburov 23.1.2008, 14:24 |
| Что-то ты и правда намудрил. Попробуй описать задачу целиком - может найдется просто иное решение. Проще и "стандартнее". |
| Автор: Platon 23.1.2008, 14:59 |
| LSD, ну на самом деле не намного проще получается :( или я просто не понял. AntonSaburov, использую библиотеку Apache MINA для организации сети. Задача: оформить синхронизированную работу функций. Вот я накидал как оно выглядит Клиентская часть http://ipicture.ru/Gallery/Viewfull/379958.html Серверная часть http://ipicture.ru/Gallery/Viewfull/379961.html Главная загвоздка находится в классе ServerConnection, как раз там необходимо усыплять потоки. |
| Автор: Platon 23.1.2008, 16:36 |
| Хм, странно, попробовал потестировать со своим ResponseWaitor'ом тест прошел, глюков и дедлоков не было... надо думать что всё таки так дело нормально пройдет, проверим еще на нескольких тачках. |
| Автор: COVD 23.1.2008, 17:39 | ||
Очевидно, вы хотите синхронные запросы пропускать через один канал связи, т.е. через один сокет. Это неестественно. Натурально будет, если для синхронного запроса открыть новое соединение, получить ответ и закрыть соединение. Используя асинхронный канал для синхронных запросов вы получаете свои трудности: - иметь коллекцию, где потоки запросов будут ожидать ответа, - иметь таймер, который мониторит коллекцию и выбрасывает потоки, у которых задержка ответа превышает таймаут, - в каждом запросе отправлять уникальный ID запроса - в каждом ответе на запрос возвращать ID запроса, чтобы отыскать поток в коллекции и разбудить его. |
| Автор: Platon 23.1.2008, 17:48 | ||
Ну, уж так уж натурально? видимо с ID придется бегать... |
| Автор: LSD 23.1.2008, 17:49 |
| Ты главное потоков побольше запусти, и дольше тестируй. P.S. У меня там ещё тайм аут обрабатывался. А у тебя как с этим? |
| Автор: Platon 23.1.2008, 17:59 |
| На самом деле никак. Я еще вечерком подумаю над тем что мне насоветовали ^_^ |
| Автор: COVD 23.1.2008, 18:02 | ||
именно так, потому что не надо синхронную схему приспосабливать к асинхронному каналу связи - никаких ID, коллекций, таймеров и блоков синхронизаций. |
| Автор: Platon 23.1.2008, 18:12 |
| COVD, это уже получается сервис? но это соединение также обслуживает асинхронные запросы. В моем примере на самом деле проблема только с тем кто разбудится. Но 100% Гарантировано, что при записи в поток запросов ответы придут в той же (ненарушенной) последовательности. |
| Автор: COVD 23.1.2008, 18:54 | ||
фактически, да. Если сиюминутная проблема только в том, "кто разбудится", то кладите потоки (т.е. обьекты, на которых они спят) в ArrayList и в том же порядке извлекайте и будите. |
| Автор: Platon 23.1.2008, 19:20 |
| Ок, логичное решение... не догадался. НО, вот будет утомительно плясать вокруг каждого такого метода... Каков же опыт RMI, на сколько я знаю там все методы сделаны в синхронном стиле. но нам плясать никак не надо. Может быть этот опыт можно повзаимствовать или придется все методы делать синхронными. |
| Автор: Platon 24.1.2008, 11:23 | ||
Свелось всё к классической задачке ^_^
|
| Автор: Platon 24.1.2008, 11:40 | ||
И получается не так уж и страшно:
|
| Автор: Platon 26.1.2008, 15:23 | ||
| Нет, вариант оказался неправильным, вот новый, но я даже не рискнул его запустить, просто не укладывается в мозгу как сделать правильно. Опытные тредеры!!! Нужна консультация.
Добавлено через 6 минут и 47 секунд Хм, нет, этот вариант конечно же завален. |
| Автор: Platon 26.1.2008, 15:49 | ||
Вот кажется валидный пример:
|
| Автор: Prol 26.1.2008, 20:51 | ||
Усыплять поток - это всё равно что хальтовать процессор в ожидании немаскируемого прерывания :о))) Моветон :о) Да посади проц в фарева цикл на обработку задач :о) |
| Автор: ivg 26.1.2008, 21:54 | ||
Мыслить в контексте однозадачности - вот моветон. Вобщем, rtfm, как говорится. |
| Автор: Platon 26.1.2008, 22:27 |
| Prol, от куда такие сведения? лупить в бесконечном цикле обработку задачи, которые поступают через неопределенные промежутки времени. Это убийство процессорного времени воистину! |
| Автор: Prol 26.1.2008, 23:24 | ||
Процессор должен работать, а человек - думать :о) Не слипайте потоки, дайте им работу :о) Если вы слипаете поток, значит он не нужен в вашей проге :о) Зачем заводить поток, который вы же сами и останавливаете? Вот классно сделано в транспьютерах: есть очередь процессоров, есть очередь задач, свободный процессор отдаётся ожидающей задаче :о) Если процессорам нечего делать, значит все задачи выполнены :о) |
| Автор: LSD 27.1.2008, 04:16 | ||||
Полная чушь! 1. Приостанавливать поток, и выполнять halt у процессора - это две большие разницы. 2. Если задача предполагает ожидание некого события, то поток должен заснуть, а не молотить никому не нужный цикл напрасно загружая процессор. Добавлено через 46 секунд
Ты не понимаешь разницы между остановкой и приостановкой? |
| Автор: Prol 27.1.2008, 11:30 | ||
А какое отношение поток имеет к задаче? Это два разных объекта :о) Если задаче нужно чего-то ожидать, то причём тут поток? Поток передаётся другой задаче :о) |
| Автор: LSD 27.1.2008, 13:39 | ||
Тяжкое наследие DOS-а, сами распределяем память, сами организуем многозадачность Во первых попробуй реализовать такой механизм, и посмотрим что у тебя получится Во вторых, что ты будешь делать если нужные данные поступили и пора возвращать управление первой задаче, а вторая задача которая заняла поток, еще и не думает заверщаться, или хуже того блокирована на IO-операции? |
| Автор: Prol 27.1.2008, 16:48 | ||||
Нет необходимости писать свое Даг Ли создал отличную открытую библиотеку утилит параллельности, util.concurrent, которая включает объекты-мьютексы, семафоры, коллекции, такие как очереди и хэш-таблицы, хорошо работающие при параллельном доступе, и несколько реализаций рабочей очереди. Класс PooledExecutor из этого пакета - эффективная, широко использующаяся, правильная реализация пула потоков, основанного на рабочей очереди. Прежде чем пытаться писать собственное программное обеспечение, которое вполне может оказаться неправильным, вы можете рассмотреть использование некоторых утилит в util.concurrent. Библиотека util.concurrent включена в Java Development Kit 1.5. Вот хороший учебник для овладения с практическими примерами. http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html |
| Автор: Platon 27.1.2008, 17:23 |
| В этом вопросе я уже не компетентен... Добавлено через 9 минут и 33 секунды хммм, в тамом случае, хотелось бы увидеть от Prol решения моей проблемы с помощью стандартного пакета Java, из этого я думаю, сможет получиться хорошая статья. |
| Автор: LSD 28.1.2008, 13:58 | ||
Из java.util.concurrent в данном случае, я вижу применимость только для Lock/Condition. Каким образом ты предлагаешь использовать PooledExecutor для данной задачи? |
| Автор: COVD 28.1.2008, 19:29 |
| Не морочьте голову Prol, java потоки - это воплощение вашей идеи с независимыми приложениями, использующими общую память. Можете гордиться |
| Автор: Prol 28.1.2008, 23:27 | ||
К сожалению все они рухнут, если произойдёт operation exeption, access violation или overflow в самой JVM. |
| Автор: COVD 28.1.2008, 23:32 |
| Ничто не вечно. |
| Автор: Platon 19.2.2008, 19:06 | ||
| Dear Lord, help me!!! Я до сих пор не могу найти решения. Мое последнее решение также впадает в ступор:
Добавлено @ 19:11 Я не уверен как правильно называется класс Flag, возможно это некий семафор. |
| Автор: SoulKeeper 19.2.2008, 22:40 |
| Я конечно понимаю что изобретение своего велосипеда делает программиста более квалифицированым, но есть 1). RMI. Правда кажись работает на блокирующем I/O, в дебри не влезаю, да и для моих потребностей, обслуживание от силы 15 клиентов, мне nio не особо и нужно. 2). JERI в Jini. В свое время обращал внимание, но в глубь копать не стал, т.к. вариант #1 подошел вполне. Кажись есть возможность использование nio. Собственно вот такие вот дела |
| Автор: Platon 20.2.2008, 10:32 |
| Зачем мне ваши технологии, когда я могу без них обойтись. Я с удовольствием перейму стандартное решение текущей задачи, но технологии мне советовать не надо. |
| Автор: SoulKeeper 20.2.2008, 11:03 |
| Вообще-то это и есть стандартные решения текущей задачи. |
| Автор: Platon 20.2.2008, 11:26 |
| задача сводится лишь к тому чтобы из асинхронной работы была возможность запросить и дождаться ответа от общего объекта, причем в пределах одной JVM. Спрашивается зачем мне RMI??? |
| Автор: Platon 20.2.2008, 13:16 | ||
Последнее из выведенного на экран оказывается всегда похожим на
Всегда заканчивается ожиданием готовности флажка. и почему то в этот момент он не срабатывает :( хотя во 2-й строчке он уже был выброшен. |
| Автор: Platon 22.2.2008, 13:20 | ||||||
Вот оно!!! Как говорится: "Эврика"!!!
Жаль, что мне никто не помог, и столько времени пришлось ломать голову над этим пустячком. Проблема оказалась вот в этом куске:
Поменял на
Добавлено через 10 минут Я бы сам себе за такие мучения орден вручил бы! |
| Автор: COVD 22.2.2008, 16:42 |
| Очень удобен для таких задач класс java.util.concurrent.LinkedBlockingQueue - никаких wait и synchronized не нужно. Единственное неудобство - эта очередь не принимает на входе null. Поэтому конец очереди , если есть в нем необходимость, можно определить только поставив в очередь специальный обьект и ловить его на выходе через instanceof . |
| Автор: Platon 22.2.2008, 16:47 |
| COVD, дорогой, где ж вы неделю назад были???!!! |
| Автор: COVD 22.2.2008, 17:40 |
| Я просто не сразу понял, с чем вы сражались. Еще мне кажется, вы не предусмотрели таймаут на ожидание ответа. Ответ ведь может никогда и не придти. А в LinkedBlockingQueue его можно поставить и тогда, если время ожидания ответа превысит таймаут, очередь выбросит null (поэтому null и запрещен на входе). |
| Автор: Platon 22.2.2008, 18:13 | ||||
Смотрим сюда.
Теперь смотрим на конец вывода в консоль:
проблемка возникла... судя по всему, в некоторые некоторые моменты poll() выдают одинаковый результат 2-м потокам. |
| Автор: COVD 22.2.2008, 18:34 |
| у меня ваш код нормально сработал - последнее выведенное число 39999. А надпись "There are .." выскакивает где-то в середине вывода на консоль, т.е. это еще не конец работы программы. |
| Автор: Platon 22.2.2008, 18:41 |
| не-не, надо несколько раз прогу запустить + если где-то в середине, увеличьте задержку до 10 секунд. |
| Автор: COVD 22.2.2008, 19:08 |
| зачем вообще эта задержка? поток, который кладет данные в очередь, может закончить свою работу в любое время. независимо от читающих |
| Автор: Platon 22.2.2008, 19:13 | ||
Ок, код некомпетентный, вот новый:
Добавлено через 2 минуты и 50 секунд Если что, сразу скажу, пробовал add/get делать синхронизированными. |
| Автор: Platon 25.2.2008, 13:54 |
| Вот и подошла к концу моя эпопея. Спасибо COVD за отличную подсказку, работа моего примера была неправильной из-за метода poll() который не ждет появления объекта в очереди, а сразу выбрасывает null. Правильным решением здесь будет take() Он точно ждет. |