Быстрый вопрос: возможно ли создать класс, содержащий внутренний бесконечный поток (пульс) и его объекты автоматически удаляются сборщиком мусора?
Длинный вопрос: я намерен создать класс, включающий внутренний бесконечный фоновый поток (например, сердцебиение). Хотя объекты этого класса не должны нуждаться в явном уничтожении и должны быть удалены сборщиком мусора, когда на них больше нет ссылок (когда в этот момент также должен быть уничтожен пульс), аналогично C#.
Проблема в следующем: Java RE не будет выполнять сборку мусора для этих объектов, потому что внутри они содержат работающий поток. Это приводит к бессмертному объекту.
Примеры:
Пример кода C# (работает как положено):
using System;
using System.Threading;
namespace HeartbeatTest
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Main execution started.");
executeMethod();
// Just wait to see some heartbeats
Thread.Sleep(5000);
// This shall garbage-collect myObject
GC.Collect();
Console.WriteLine("Main execution finished.");
}
private static void executeMethod()
{
Console.WriteLine("executeMethod() execution started.");
MyObjectWithHeartbeat myObject = new MyObjectWithHeartbeat();
Console.WriteLine("executeMethod() execution finished.");
}
}
class MyObjectWithHeartbeat
{
private Thread heartbeatThread;
public MyObjectWithHeartbeat()
{
heartbeatThread = new Thread(() =>
{
try
{
while (true)
{
Console.WriteLine("heartbeat...");
Thread.Sleep(1000);
}
}
catch (ThreadInterruptedException)
{
// finish heartbeat execution
}
});
heartbeatThread.Start();
}
~MyObjectWithHeartbeat()
{
Console.WriteLine("MyObjectWithHeartbeat destroy");
heartbeatThread.Interrupt();
}
}
}
Вывод С#:
Main execution started.
executeMethod() execution started.
executeMethod() execution finished.
heartbeat...
heartbeat...
heartbeat...
heartbeat...
heartbeat...
MyObjectWithHeartbeat destroy
Main execution finished.
Пример кода Java (не работает):
package heartbeattest;
public class Main {
public static void main(String[] args) {
System.out.println("Main execution started.");
executeMethod();
// Just wait to see some heartbeats
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// This should garbage-collect myObject
System.gc();
System.out.println("Main execution finished.");
}
private static void executeMethod() {
System.out.println("executeMethod() execution started.");
MyObjectWithHeartbeat myObject = new MyObjectWithHeartbeat();
System.out.println("executeMethod() execution finished.");
}
}
class MyObjectWithHeartbeat {
private Thread heartbeatThread;
public MyObjectWithHeartbeat() {
heartbeatThread = new Thread(new Runnable() {
@Override
public void run() {
try {
while (true) {
System.out.println("heartbeat...");
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
heartbeatThread.start();
}
@Override
protected void finalize() throws Throwable {
System.out.println("MyObjectWithHeartbeat destroy");
heartbeatThread.interrupt();
super.finalize();
}
}
Вывод Java:
Main execution started.
executeMethod() execution started.
executeMethod() execution finished.
heartbeat...
heartbeat...
heartbeat...
heartbeat...
heartbeat...
heartbeat...
Main execution finished.
heartbeat...
heartbeat...
heartbeat...
heartbeat...
heartbeat...
heartbeat...
...
(it keeps executing)
Существует ли архитектурный шаблон для преодоления этого тупика JRE "поток продолжает работать, потому что объект существует - объект не уничтожен, потому что поток работает"?