| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Java: Общие вопросы > Потоки |
| Автор: GIK 13.1.2006, 17:47 | ||
| Всем привет. В данный момент разбираю потоки, и у меня возникло пара вопросов. 1) Почему обращение Thread.sleep(500); происходит именно так, а не t.sleep(500);, что для меня логичней было бы, т.е. почему обращаются именно к классу Thread, а не к его экземпляру. 2) Еще мне не понятна конструкция Thread.sleep(500); тем что она может вызвать исключение типа InterruptedException , ЕСЛИ бы кокой нибуть поток прервал его ожидание. Как я понял потоком который прерывает ожидание, может является ГЛАВНЫЙ поток, НО в свою очередь потоки используют процессор ВМЕСТЕ. Тут то я и запутался окончательно. Вот код:
|
| Автор: COVD 13.1.2006, 20:20 |
| Thread.sleep(500); то же самое, что и Thread.currentThread().sleep(500), т.е. на самом деле текущий поток тормозится. А прервать его может любой другой поток, имеющий ссылку на текущий. sleep() надо использовать если вы не предполагаете его прерывать. Если же вы хотите поток "разбудить" из другого потока, то надо использовать wait() - notify(). |
| Автор: GIK 14.1.2006, 10:38 | ||||||||
Т.е. Thread - это всегда поток который выполняется ?
Понял.
А как эта ссылка может реализоваться, именно в данном примере, и именно на дочерний поток? |
| Автор: LSD 14.1.2006, 17:05 | ||||||
Не совсем. Thread - это класс, а Thread.sleep(500) - это вызов статического метода у этого класса. Просто он вызывает засыпание для того потока из которого был вызван.
Так:
|
| Автор: GIK 18.1.2006, 13:25 | ||
| Извяюсь что поднимаю старый вопрос, просто возникли непонятки. Почемуто при запуске потока в экземпляре b (B b = new B(a,"super");), сразу через run(), реализуется только один поток (действие), т.е. другие, пока незакончится этот, просто бездействуют? И еще странно что t.sleep(1000); вроде как работает, но вызова public void put() до этого момента небыло?
|
| Автор: powerOn 18.1.2006, 14:17 |
| Если запускаешь run(), то выполнится метод run()... поток не создается. Поток создает именно метод start(), создает, а потом как говорится в отдельном контексте (или псевдопаралельно) запускает метод run(). Так что простой запуск run() аналогичен простому методу (без параллельного выполнения). |
| Автор: GIK 18.1.2006, 14:23 | ||
А как тогда осуществляется остановка t.sleep(1000) ? Она ведь осуществляется? В смысле после запуска run. |
| Автор: LSD 18.1.2006, 14:31 |
| Метод sleep() статический, и хотя ты можешь вызвать его от экземпляра, но это все равно эквивалентно Thread.sleep(). И тормозится, текущий поток. |
| Автор: GIK 18.1.2006, 14:48 | ||
Понял. А как же остальные потоки, почему они не включаются? Мое предположение, что из-за того что run был запущен не через put(), и по этому возврата к главному потоку не было? Добавлено @ 14:53 В смысле сразу невключаются. |
| Автор: LSD 18.1.2006, 14:59 |
| У тебя в конструкторе B(A a, String s) вначале вызывается просто метод run() и соответсвенно Thread.sleep() вызывается для потока main. Потом, создается новый поток и метод run() вызывается у него, и соответвенно Thread.sleep() действует уже для него. Поскольку у тебя потоки все таки создаются в итоге, то и метод t.join() срабатывает. |
| Автор: GIK 18.1.2006, 15:14 |
| Тут либо я чето недопонимаю, либо вопрос задал не правильно. После запуска run и первой остановки t.sleep(1000) запуск put(); СРАЗУ не происходит, и вообще ничего СРАЗУ, после run () не происходит, в том числе возврат к созданию третьего экземпляра B b2 = new B();. Вот я и думаю, что возврат к остальным потокам (действиям), происходит только после вызова через t.start()? Т.е. только он имеет характеристики возврата к другим потокам (действиям), а метод t.join() вообще инициализируется только после третьего экземпляра B b2 = new B();. |
| Автор: LSD 18.1.2006, 16:47 |
Программа работает так:
|
| Автор: GIK 18.1.2006, 17:11 |
| Ща не могу проверить, но по памяти вывод такой: BlaBla BlaBla Potok GoOOOOOOOOOO1 Potok GoOOOOOOOOOO2 Potok GoOOOOOOOOOO3 Potok GoOOOOOOOOOO4 Potok GoOOOOOOOOOO5 А потом все остально неважное. Так вот, почему его не прерывают остальные потоки, как если бы его запустили через put(); ? |
| Автор: LSD 18.1.2006, 17:48 | ||
На самом деле вывод такой:
|
| Автор: GIK 18.1.2006, 17:59 |
| Тфу блин, перепутал цифры. Ну да такой, ну дак что как это объяснить? |
| Автор: LSD 18.1.2006, 18:10 | ||||
Выполняется вызов метода run() из потока main, это порождает следующий вывод:
затем происходит запуск еще 2-х потоков, потоки начинаю работать почти одновременно и потому вывод из них идет по очереди, и соответсвенно получаем:
|
| Автор: GIK 18.1.2006, 18:25 |
| Как объяснит тот факт, что после вызова run() напрямую, не через put(), другие потоки НЕ реализуются СРАЗУ (они ждут), через put() допустим, после вызова run() сразу происходит возврат к главному потоку, и они используют процессор как бы вместе. Но так не происходит если вызвать run() напрямую, т.е. не происходит возврата к другому(другим потокам), он использкет его один на все время затраченное на for цикле. Или может, просто мне думать, что так оно есть и непарится, невникать в суть? Хотя очень интересно. |
| Автор: COVD 18.1.2006, 19:59 |
| Как уже здесь писали, для запуска потока предназначен start(), который вызывает run(). Если программа вышла из run(), то поток умер и повторному использованию не подлежит. Метод run() напрямую не вызывают. И выяснение, что будет в случае прямого обращения к run(), имеет скорее академическую, но не практическую ценность. |
| Автор: LSD 18.1.2006, 22:30 |
| У тебя есть работающий поток. В рамках одного потока команды выполняются последовательно одна за одной, можно только изменить порядок их выполнения (это делают управляющие операторы if, for, break и т.д.). Поэтому когда ты пишешь такой код: run(); то ты просто передаешь управление в метод run, далее выполняются все команды из этого метода и ты продолжаешь с того места, где закончил. Именно этим и объясняется, поведение программы в первом случае. Теперь рассмотрим, второй случай. Ты вызываешь метод put() (все это происходит в потоке main), создаешь в этом методе объект типа Thread (кстати ты даешь ему в качестве аргумента объект который реализует интерфейс Runnable, вот тебе хороший пример использования интерфейсов. Когда разрабатывался класс Thread, никто не знал о твоем классе, но им было достаточно знать, что он будет реализовывать Runnable, значит в нем будет метод run и его можно будет вызвать.) Создал объект, после чего вызываешь метод start(), который запускает новый поток, метод start() не ждет пока поток отработает, он просто дает сигнал на запуск и возвращается. Запущенный поток, иниализируется и выполняет метод run у объекта переданного в качестве аргумента. Там уже свой поток выполнения команд, независящий от потока который его запустил. Запустивший поток может закончить свое выполнение, но это никак не влияет на этот поток. P.S. А вообще, тебе надо почитать какую нибудь книжку, на тему многопоточного программирования. |
| Автор: Galaran 11.7.2009, 20:39 |
| Чтобы не плодить топики спрошу здесь: Решил написать простой сервер чата и столкнулся с проблемой. Архитектура такова: Есть один главный поток(принимает новые соединения), который создает объекты Connection(для каждого клиента - свой). При этом занося их в мэп вида (clientId : connection). В класс Connection инкапсулирован поток прослушивания пакетов от клиента. Если поступает пакет с сообщением, этот поток обращается к синглтону EventHandler(защищен - к нему может одновременно обращаться с запросом обработать событие только один коннект), он обращается в мэпу и рассылает сообщения клиентам. При таком подходе сразу возникла проблема: Клиент может разорвать коннект или же коннект может разорваться в случае ошибки. При этом надо как-то удалить из хеш-массива запись этого коннекшена и остановить соответствующий поток. Из этого потока, в котором возникла ошибка это сделать не выйдет(или выйдет ? он же удалит сам себя из хэшмэп, но при этом будет ещё выполняться и удачно завершится. Не опасно ли это?) Т.е, как я понимаю, надо создать поток-демон для отслеживания таких вот отвалившихся клиентов и посылать ему сообщение(как ?), если клиент отвалился. При этом поток коннекшена завершится, а демон удалит из хеш-массива этот коннекшн. Подскажите как лучше в данном случае построить архитектуру, и где об этом можно почитать |
| Автор: Galaran 12.7.2009, 10:11 |
| Вопрос снят, нашёл здесь: http://www.javatalks.ru/sutra39952.php |