2011-07-21 19 views
2

我知道每当垃圾收集器收集一个类实例时,都会调用finalize()。但是,当通过队列将一个类的实例传递给另一个线程时,我有点困惑。什么时候会在这个场景中调用我的类实例的finalize()?

比方说,这是线程1的骨架:

for(i=0; i<1000; i++) { 
    Packet pkt = new Packet(); // instance of class 
    pkt.id = i; 
    thread2.queue.put(pkt); 
} 

然后,线程2会从队列中取出包,并进行长时间的操作。这第二个线程是否获得了数据包的“副本”,还是通过某种形式的参考?重要的是,如果是通过复制,线程1中创建的实例的finalize()可以在线程2完成数据包之前调用。如果是通过引用,我保证finalize()只会被调用一次来获取数据包中的信息。

这个基本的例子可能不显示重要性,但我在数据包中存储一个C指针(来自JNI),以便在完成对象时销毁一些内存。如果它通过复制传递,内存可能会在第二个线程完成之前被销毁。如果它通过引用传递,那么只有在GC看到它不再被两个线程使用时(我期望的行为),它才应该被销毁。如果后一种情况不能保证,我不会使用finalize()并使用其他的东西,但它会更复杂。

+0

java方法参数最接近的C/++比较是它们是一个按值传递的指针。所以它是通过复制,但它只是指针的副本。 (唯一的操作是取消引用。)只要系统中有一个指针指向对象的位置,该位置就不会被收集。 – Affe

+0

我强烈建议你为数据包添加一个清理方法来清理C指针,而不是依赖于finalize方法,或者甚至使用finalize方法 –

回答

6

第二个线程接收相同的实际对象实例。你可以避免过早敲定。

它接收到对象引用的副本,如果你想这样想。

此外,finalize不一定在垃圾回收器发现该对象已成为垃圾时运行 - 虚拟机随后可以随时运行它,并在此之后实际回收内存。当finalize将运行时,你真的不能信赖。但是,由于您在意的是知道finalize不会在第二个线程完成对象之前调用,这是不重要的。但值得了解!

+0

太棒了!非常感谢您的快速回复。这大大简化了我的工作:) – gnychis

+1

在finalize()运行之前不会收集对象!覆盖finalize的对象将被放入一个在低优先级线程中处理的终结器队列中。这是你应该避免finalize()的另一个原因。 –

+0

@Damokles:当然是非常正确的。我的措辞很sl,,谢谢指出。我已经将它改写为希望更准确。 –

相关问题