![]() |
Модераторы: LSD, AntonSaburov |
![]() ![]() ![]() |
|
simanyay |
|
||||
![]() Антон Ковалёв ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 2053 Регистрация: 22.8.2002 Репутация: 3 Всего: 36 |
Привет. Вот только вчера связался с многпоточным программированием в Java и тут же вопрос:
Как мне остановить поток? Я пытаюсь с помощью wait(), но поток не останавливается. Мало того, основной поток ждёт конца его выполнения. Вот код:
Вызов:
Надеюсь на Вашу помощь. Заранее благодарен. P.S. При проигрывании музыки через AdvancedPlayer, приложение полностью виснет до конца песни. Поэтому мне и нужно выделить его в отдельный поток -------------------- «It's better to be a pirate than to join the Navy» — Steve Jobs. |
||||
|
|||||
Domestic Cat |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5452 Регистрация: 3.5.2004 Где: Dallas, US Репутация: 50 Всего: 172 |
Вот что Вы делаете:
1. Запускаете поток (он выполняет play()) 2. из main вызываете pause то есть поток 1 (SoundPlayer) играет play поток 2 (main) выполняет wait и останавливаетса Если хототе сделать паузу, то скорее всего должен быт метод типа pause у самого плеера.
Это сообщение отредактировал(а) Domestic Cat - 17.6.2004, 22:28 -------------------- |
|||
|
||||
LSD |
|
|||
![]() Leprechaun Software Developer ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 15718 Регистрация: 24.3.2004 Где: Dublin Репутация: 210 Всего: 538 |
Есть 2 варианта:
1) Thread.stop() - но он не рекомендуется так как может вызывать блокировки 2) попытаться у player вызвать метод stop() -------------------- 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. |
|||
|
||||
Domestic Cat |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5452 Регистрация: 3.5.2004 Где: Dallas, US Репутация: 50 Всего: 172 |
Может, чего-нибудь в фак по потокам накропать?
-------------------- |
|||
|
||||
Sun |
|
|||
Account removed ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 1611 Регистрация: 14.8.2002 Репутация: 8 Всего: 48 |
Отличная идея, если вам не трудно, будем очень признательны ![]() -------------------- Account removed |
|||
|
||||
cardinal |
|
|||
![]() Инженер ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 6003 Регистрация: 26.3.2002 Где: Германия Репутация: нет Всего: 99 |
Я сделал одну глобальную переменную и управлял ей всем потоком. Поможет это тебе или нет я не знаю, т.к. твой код в Java для меня выглядит довольно непривычно
![]() Прочитай мое сообщение от 28.10.2003, 16:41 вот тут (в нем говорится об остановке цикла, но это не суть - принцип тот же): http://forum.vingrad.ru/index.php?showtopi...оток,and,глобал -------------------- Немецкая оппозиция потребовала упростить натурализацию иммигрантов В моем блоге: Разные истории из жизни в Германии "Познание бесконечности требует бесконечного времени, а потому работай не работай - все едино". А. и Б. Стругацкие |
|||
|
||||
Domestic Cat |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5452 Регистрация: 3.5.2004 Где: Dallas, US Репутация: 50 Всего: 172 |
2Cardinal
Я че-то не поиму, а как связан VB с Java? В Java глобальных переменных нет, кстати. Sun ok segodnja posizhu, esli uspeju - sdelaju post zdes' ![]() PS. a kak pri ispravlenii iz translita v russkii peregnat ![]() Это сообщение отредактировал(а) Domestic Cat - 18.6.2004, 15:13 -------------------- |
|||
|
||||
Sun |
|
|||
Account removed ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 1611 Регистрация: 14.8.2002 Репутация: 8 Всего: 48 |
Я могу потом подредактировать. Можете вставить ответ прямо в этой теме, а я поправлю транслит на кириллицу и перенесу этот пост в FAQ. -------------------- Account removed |
|||
|
||||
cardinal |
|
|||
![]() Инженер ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 6003 Регистрация: 26.3.2002 Где: Германия Репутация: нет Всего: 99 |
Никак, но поток он и в Африке поток ![]() -------------------- Немецкая оппозиция потребовала упростить натурализацию иммигрантов В моем блоге: Разные истории из жизни в Германии "Познание бесконечности требует бесконечного времени, а потому работай не работай - все едино". А. и Б. Стругацкие |
|||
|
||||
Sun |
|
|||
Account removed ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 1611 Регистрация: 14.8.2002 Репутация: 8 Всего: 48 |
Вместо глобальных переменных используются статические переменные класса. Статическая переменная существует в одном экземпляре для данной виртуальной машины. -------------------- Account removed |
|||
|
||||
Domestic Cat |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5452 Регистрация: 3.5.2004 Где: Dallas, US Репутация: 50 Всего: 172 |
Napisal, tol'ko teper' zapostit' ne mogu - pochemu-to poluchaetsja odna ]
![]() Это сообщение отредактировал(а) Domestic Cat - 18.6.2004, 19:15 -------------------- |
|||
|
||||
Domestic Cat |
|
||||||||||||||||||||||||||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5452 Регистрация: 3.5.2004 Где: Dallas, US Репутация: 50 Всего: 172 |
Синхронизация потоков
Если на вашем компьютере один процессор, то в данныи момент времени может выполняться может только один поток - все остальные потоки приостановены (suspended). Планировшик занимается переключением потоков и распределением времени их выполнения. Отсюда 2 вывода: - Thread.sleep(int ms) не обязателно "спит" именно ms миллисекунд. Когда поток "проснется" зависит от планировшика. - установка приоритета потока - всего лишь пожелание; это значит что скорее всего поток с приоритетом 9 получит больше времени на исполнение чем поток с приоритетом 8. Хотя для HotSpot наверное, так и будет, а вот для браузеров - вряд ли. 2. Перейдем собственно к синхронизации. Зачем она нужна? Посмотрим на такую программу:
Если запустить ее: java Test <N> то она запустит N потоков, передав каждому ссылку на объект класса А; ну а потоки вызывают метод которыи меняет статическую переменную а1, переменную объектa а2 и локальную переменную а3. Если запустить один поток, то мы увидим, естественно:
A вот для 100 потоков результат будет инои:
Получилось так потому, что а1 и а2 не thread-safe. Дело в том, что при создании каждыи поток получает свои участок памяти (он называется "рабочая память") на стеке; и соответственно, каждыи поток получает свою копию локальних переменных. Именно поэтому а3 всегда в результате равно 0 - каждыи поток оперирует своей а3. Локальные переменные всегда thread-safe. Проблема возникает для переменных класса и объекта. Oбъект создается на хипе (heap - куча), потоки получают копию ссылки на объект, и поетому работают с одним и тем же объектом. Поскольку мы не знаем как планировшик распределит время выполнения между потоками, то и предсказать результат невозможно: попав внутрь метода doWork() поток изменяет а1, а2, и останавливается (sleep); в это время другие потоки изменяют а1, а2. В резyльтате для потока а1 и а2 до sleep бутут иными чем после sleep. В целом проблема в следуюшем : поскольку потоки имеют доступ к не- thread-safe переменным, и действия планировшика неопредсказуемы, получается что программист ограничен работать только с локальными переменными в многопотоковом коде; иначе результаты предсказать нелзя. 3. Чтобы снять это ограничение, и введена синхронизация. Каждыи объект в Java получает "лок" (lock - замок); и этот лок только один. Встретив слово synchronized поток пытается забрать лок у объекта; если ему ето удается, он попадает внутрь (метода или блока). Если второи (третии итп) потоки попытаются теперь выполнить любой synchronized метод или блок на данном объекте, они не смогут получить лок и будут приостановлены. После того как поток покидает synchronized блок, он возврашяет лок объекту и ждушие потоки начинают "борьбу" за лок (это называется "concurrent access"). Заметим, что на не-synchronized методы/kод это не распространяется, даже если один из потоков взял лок, не-synchronized методы могут быть вызваны любым количеством потоков одновременно. Переделаннаыа программа быдет иметь вид:
Результат будет такои:
Чем меньшии блок вы синхронизируете, тем лучше. Запустив этот код вы увидите что скорость по сравнению с первои программои значительно снизилась. Если раньше потоки выполняли метод одновременно, то теперь - по очереди, что и снижает скорость. Понятно что для нескольких потоков код :
будет всегда выгоднее чем:
Синхронизируя метод, мы синхронизируем на объекте "this" (то есть поток будет забирать лок у самого объекта ); но никто не мешает синхронизировать на любом другом объекте:
4. Теперь посмотрим на такую программу:
Задумка такая : один поток считает, второй "подбирает" результат. Все бы хорошо, но опять проблема: результат будет зависеть от порядка старта потоков: для p1.start(); p2.start(); мы получим 100, а для p2.start(); p1.start() - 0. Дело в том, что потоки понятия не имеют друг о друге; во втором случае поток 2 (p2) получает значение переменнои раньше чем p1 успевает его посчитать. Да и то что в первом случае результат будет всегда 100 при повторных запусках никто не гарантирует - неизвестно успеет ли p1 закончить вычисления до того как p2 затребует результат. Для коммуникатции потоков используыутся методы wait(), notify() и notifyAll(). wait заставяет поток остановиться и выпустить лок; так что другои поток (ждушии "снаружи" synchronized) сможет его затребовать и воити в блок/метод. notifyAll сообшает всем ждущим на wait потокам, что данныи поток собирается выпустить лок (ну а notify - одному из ждуших потоков, первом попавшим на wait). Как это работает мы посмотрим на исправленном варианте кода:
Возможны 2 варианта: a. p2 пытаетса выполнить getResult, и получает лок от объекта a. Поскольку isReady равен false, p2 попадает в цикл, выполняет wait и отпускает лок. p1 попадает в doWork, считает, изменяет isReady и уведомляет (notify) p2 что все готово. p2 выходит из цикла и получает результат. б. p1 первым попадает в doWork; он получает лок, изменяет isReady и выполняет notify которыи ничего не делает, посколку p2 попросту не может попасть внутрь getResult. p1 отдает лок, p2 его получает, благополучно пропускает цикл и получает результат. Здесь результат уже от порядка вызова методов зависеть не будет и всегда равен 100. Заметим, что без wait/notify это работать не будет! Если wait убрать, поток p2 будет крутить цикл "вхолостую", отнимая ценные ресурсы; но это не главное. Проблема возникнет если p2 первым получит лок - он навсегда останетса в цикле, в то время как p1 не сможет попасть в doWork. Такая ситуация называетса deadlock. Вот более красивыи пример:
Пусть p1 получил лок на объекте a, а p2 - на объекте b. Для продолжения работы p1 нужно получить лок от b - но этот лок у p2; соответственно, p2 нужен лок от b, но он у p1! 5. Наконец, последнее. На самом деле поток может кэшировать переменных (хотя он и имеет ссылку на соответствующий объект на хипе). Рассмотрим этот вопрос на примере переменных а1 и а2 из первой программы. Java хранит значения переменных а1 и а2 в так называемой "главной памяти" ("main memory"). Тем не менее поток может сохранить значение этих переменных "для себя", чтобы не обновлять их каждый раз. В результате значения переменных у различных потоков будут несогласованными. Если вы хотите, чтобы поток каждый раз "освежал" значение переменной, получая его из main памяти, используйте volatile, например:
Проверить действие volatile можно с помошю модификации первого примера:
Поскольку а1 синхронизируется с главной памятью, а а2 - нет, то при запуске java Test 1000 вы получите что-то вроде:
Как видим, потоки закэшировали а2, в результате чего каждый поток изменяет свою копию а2, в то время как а1 синхронизирована на всех потоках. Это сообщение отредактировал(а) Domestic Cat - 19.6.2004, 01:50 -------------------- |
||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||
Domestic Cat |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5452 Регистрация: 3.5.2004 Где: Dallas, US Репутация: 50 Всего: 172 |
Хм, в случае с volatile я не учел цто пока поток пытается напечатать а1 и а2 другие потоки могут их
изменит. Сегодня попробовал запустить - что с volatile что без, разницы нет. Где-то я читал что volatile штука загадочная, на некоторых JVM он на работает. -------------------- |
|||
|
||||
Sardar |
|
|||
![]() Бегун ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 6986 Регистрация: 19.4.2002 Где: Нидерланды, Groni ngen Репутация: 4 Всего: 317 |
По идее это volatile переменные изменяемые внезапно железом, компилятор при каждом обращении к такой переменной должен обновлять ее значение.
-------------------- Опыт - сын ошибок трудных © А. С. Пушкин Процесс написания своего велосипеда повышает профессиональный уровень программиста. © Opik Оценить мои качества можно тут. |
|||
|
||||
ElectricalStorm |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 547 Регистрация: 22.1.2004 Репутация: 5 Всего: 9 |
Domestic Cat - интрересно
-------------------- Нужно знать инструмент, которым пользуешься |
|||
|
||||
![]() ![]() ![]() |
Правила форума "Java" | |
|
Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic. |
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Java: Общие вопросы | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |