#java #multithreading #for-loop #jvm
Вопрос:
Я понимаю, что если я создам некоторую переменную внутри цикла в главном потоке, она создаст ее, затем на следующей итерации она создаст другую с тем же именем и будет продолжаться до тех пор, пока цикл не будет завершен. Нет проблем, потому что на каждой итерации созданная переменная исчезает, поэтому мы можем создать еще одну.
Но что, если я создам потоки с тем же именем в цикле. Потоки не «завершаются» одновременно. Так почему же это возможно? Я чувствую, что мне следует отделить работу JVM с созданием переменных и работу ОС с обработкой потоков, но я хочу услышать правильное объяснение.
for (int i = 0; i < 10; i ) {
MyFirstThread thread = new MyFirstThread();
thread.start();
}
Комментарии:
1. Сам объект может все еще существовать, но переменная , которая ссылается на него, вышла из области видимости. Область видимости-это концепция, которая имеет смысл только во время компиляции, а не во время выполнения.
2. Имена переменных доступны для вашего удобства. Они не существуют во время выполнения.
3. @Michael Я не думаю, что проблема операции связана с областью действия, я думаю, что дело в разнице между переменными и ссылочными объектами. Таким образом, связанный вопрос может оказаться бесполезным.
4. @RalfKleberhoff Согласен, я передумал
5. Обратите внимание, что вы даже можете сделать это без какой-либо переменной вообще, и пусть тело цикла будет просто
new MyFirstThread().start()
для того же эффекта.
Ответ №1:
Вы смешиваете объекты (экземпляры классов) и переменные. Это две совершенно разные вещи в Java.
Вы можете создавать объекты с new
помощью оператора, как в new MyFirstThread()
. С этого момента они существуют «вечно», пока сборщик мусора не обнаружит, что они больше не нужны, что для потока не произойдет до его завершения.
Переменная может содержать ссылку на объект. И до тех пор, пока на объект ссылается переменная, сборщик мусора не будет его трогать.
Теперь в вашем коде
for (int i = 0; i < 10; i ) {
MyFirstThread thread = new MyFirstThread();
thread.start();
}
Допустимая (но упрощенная) интерпретация состоит в том, что вы десять раз
- создайте переменную с именем
thread
, - создайте объект класса
MyFirstThread
и сохраните ссылку на этот объект в переменной, - запустите эту тему,
- избавьтесь от переменной
thread
(когда выполнение завершится в}
конце итерации = конец области действия переменной).
Ключевым моментом является то, что удаление переменной не влияет на объект, на который она ссылается. До тех пор, пока у этого объекта есть причина продолжать свое существование (например, поток все еще работает), он будет оставаться живым и продолжать выполнять свою работу.
Во время цикла, например, на второй итерации, первая thread
переменная больше не существует, но первый MyFirstThread
экземпляр все еще существует и выполняется.
Аналогия:
Представьте, что экземпляры MyFirstThread-это дома, а переменные-листы бумаги, на которых вы указываете адрес дома.
Затем вы делаете это десять раз:
- возьмите чистый лист бумаги,
- постройте дом в каком-нибудь месте и запишите адрес на листе бумаги,
- используя адрес из вашего листка, прикажите кому-нибудь непрерывно косить газон (извините, не идеальная аналогия).,
- выбросьте лист бумаги.
В конце концов, там будет десять домов с идеальными газонами, но вы не сможете получить к ним доступ, так как больше не знаете, как их найти.
Комментарии:
1.На случай, если опу не все равно,…
Thread
Причина, по которой экземпляр не собирается во время выполнения потока, проста: вызов метода не является нижней частью стека потока.run()
Какая-то функция в JVM вызываетrun()
, и у этого вызывающего абонента есть локальная переменная, содержащая ссылку наThread.currentThread()
экземпляр. Локальная переменная вызывающего объекта продолжает существовать, по крайней мере, до тех пор, покаrun()
не вернется или не возникнет исключение.2. @IngvarKokorin Здесь все еще, кажется, есть какое-то неправильное представление, поэтому я немного расширю свой ответ.
3. Это не отличается, например
for (int i = 0; i < 10; i ) { Frame f = new Frame(); f.setVisible(true); }
, от . Некоторые операции, например методstart()
Thread
илиsetVisible
изFrame
, могут привести к тому, что на объект будет ссылаться служба, предоставляемая самой средой выполнения. Существуют методы, такие какThread.getAllStackTraces().keySet()
илиFrame.getFrames()
, которые позволяют находить эти все еще активные объекты, даже если у вас еще нет локальной ссылки на них.4. @IngvarKokorin, Прочтите, что Ральф добавил к своему ответу-немного о домах и листках бумаги. Ответ: «Это не та же самая ссылка…» Это все равно что сказать, что карточка, которую я вам дал с адресом дома, не такая же, как та, которую я дал кому-то другому. Хорошо, карты не одинаковые, но они оба относятся к одному и тому же дому. В Java, если у меня в программе есть
Thread t =...
, а затем,Thread u = t;
, то да,t
иu
это разные переменные, но они оба относятся к одному и тому жеThread
экземпляру. GC не восстановит этот экземпляр до тех пор, пока не останется переменных, которые ссылаются на него.5. @Holger по аналогии с моим домом, использование статических
Thread
методов означало бы обратиться в какой-нибудь местный орган власти и спросить их о домах, принадлежащих мне.
Ответ №2:
Вы просто назначаете ссылку на новый пользовательский объект MyFirstThread
новой переменной thread
. В каждом цикле цикла переменная thread
выходит за рамки, и вы теряете ссылку на MyFirstThread
созданную и новую переменную thread
.