подход к обнулению всех ссылок на объекты, созданные Java ThreadFactory

У меня есть реализация Java ThreadFactory, порождающая объекты подкласса исполняемых потоков в моем приложении для Android. Это приложение требует, чтобы все порожденные потоки были адресуемыми до того, как сработает определенное событие, и чтобы после срабатывания указанного события порожденные потоки могли стать пригодными для сборки мусора (например, счетчик ссылок равен 0). Я думал, что для удовлетворения первого требования я просто буду поддерживать ArrayList моих объектов потока, и это прекрасно работает. Проблема связана со вторым требованием и привела меня к ряду вопросов, касающихся подсчета ссылок Java:

Вопрос 1. Увеличивает ли простое сохранение ссылок на порожденные потоки в ArrayList или другом контейнере счетчик ссылок каждого объекта потока? Каким был бы счетчик ссылок каждого объекта потока, если бы я никогда не сохранял их, а вместо этого позволял своей фабрике создавать их и запускать без какого-либо определенного дескриптора, как показано ниже?

mvThreadSource.newThread(new BackgroundThread(...)).run();

Вопрос 2. Делает ли приведенный ниже пример кода что-либо с фактическим объектом потока, на который указывает hTempThread, кроме увеличения и немедленного уменьшения его счетчика ссылок?

BackgroundThread hTempThread;
for(int i=0;i<mvThreadsVector.size();i++){
    hTempThread = mvThreadsVector.get(i); //probably increments ref count of thread
    hTempThread = null; //probably just decrements the ref count of thread back to 
                        //previous value
}

Вопрос 3. Предполагая, что ответ на вопрос 2 «нет», каким будет эффективный способ хранения потоков, порожденных реализацией ThreadFactory, чтобы их счетчики ссылок можно было уменьшить до 0 по требованию? Каким будет правильный синтаксис при удалении этих ссылок? Будет ли приведенный ниже пример кода эффективно уменьшать количество ссылок на все задействованные объекты (mvThreadsVector, tempThreads, каждый объект потока, отслеживаемый mvThreadsVector) до 0? Что именно делает clear() со счетчиками ссылок на объекты, хранящиеся в массиве массивов, и что установка ссылки на массив в null делает со счетчиками ссылок на элементы, хранящиеся внутри (если вообще есть)?

Object[] tempThreads = mvThreadsVector.toArray();
mvThreadsVector.clear(); //possible this line is all I need...
mvThreadsVector = null;
for(int i=0;i<tempThreads.length;i++){
    tempThreads[i] = null;
}
tempThreads = null;

Любая помощь с любым/всеми вышеперечисленными вопросами будет очень признательна!


person CCJ    schedule 29.01.2013    source источник
comment
Предложите вам разбить это и задать несколько вопросов.   -  person Aaron Kurtzhals    schedule 30.01.2013


Ответы (1)


  1. Если у вас запущен поток, до тех пор, пока он не завершит выполнение, он будет храниться в памяти (или заменен), но не GC. Даже если в потоке нет вашего кода, ссылающегося на него, но он выполняет код, он имеет по крайней мере внутреннюю ссылку.

  2. Вы даже не можете гарантировать, что он будет увеличивать и уменьшать счетчик ссылок. Компилятор может оптимизировать его, поняв, что первое присваивание не имеет никакого эффекта (поскольку оно немедленно перезаписывается), и удалить его.

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

Я думаю, что основная проблема заключается в том, что вы не должны рассчитывать на то, что счетчик ссылок потоков упадет до 0; пока они работают, вы должны предполагать, что у них есть ссылки, поэтому у вас также должен быть способ убедиться, что поток останавливает свое выполнение.

person Luis    schedule 30.01.2013
comment
ладно, я примерно так и думал. Учитывая, что если у вас запущен поток, пока он не завершит выполнение, он будет храниться в памяти (или заменен), но не GC, что произойдет с потоком, если его выполнение никогда не останавливается до закрытия приложения? Будет ли система освобождать выделенную потоку память (текущий системный контекст — Android 2.3.3, хотя понимание обработки JVM в этой ситуации также было бы полезно)? Спасибо! - person CCJ; 30.01.2013
comment
Грамотное завершение работы подразумевает остановку всех потоков (не с помощью Thread.stop, не самая лучшая идея), а какой-то другой механизм. В этот момент приложение само остановится. Менее мягкое завершение работы (т. е. завершение приложения/процесса) освободит всю память, включая потоки, работающие в ней. Поток всегда выполняется внутри содержащего процесса/приложения, потоки не владеют ресурсами, а процессы. - person Luis; 30.01.2013