假设我有 -
public class ThreadingIssue {
public B b = new B();
}
class B{
private final Object lock = new Object();
public void someMethod(int timeOut){
synchronized(lock){
try{
lock.wait(timeOut);
}catch(Exception e){
}
// some task..
lock.notifyAll();
}
}
}
class Thread1 implements Runnable{
private ThreadingIssue t;
public Thread1(ThreadingIssue issue) {
t = issue;
}
public void run(){
while(true){
t.b.someMethod(5000);
}
}
}
class Thread2 implements Runnable{
private ThreadingIssue t;
public Thread2(ThreadingIssue issue){
t = issue;
}
public void run(){
try{
Thread.sleep(2000);
}catch(Exception e){
}
t.b = null;
}
}
Thread1会发生什么,如果它在B的someMethod(5000)
内并等待锁定,并且Thread2使B的对象为空?我不确定Thread1是否会抛出哪个异常..任何帮助?
答案 0 :(得分:3)
第二个线程保存对正在运行其方法的对象的引用(否则它将无法运行其实例方法),因此GC无法处置该对象,因此不存在异常。
在您执行
时更明确地使用您的代码t.b.someMethod(5000)
JVM内部处理t.b
表达式(对象的引用),因此引用计数不为0.
答案 1 :(得分:1)
总结SJuan76和op的讨论:
看起来有两个对t的引用,但只有一个对b(t中的一个)。
t不会被释放,因为线程独立地保持它。但是,b可能会被删除(取决于gc),因为一旦引用无效,其引用计数将降至零
所以Thread2可能会抛出NullPointerException。
编辑:
在someMethod()中,b对象不会被释放,因为this
指针保持在堆栈上,至少使ref计数为1。每次执行成员方法都可以说同样的事情,因为每个成员方法都会以this
作为参数。
请注意,虽然您获得了NullPointerException,但这并不意味着对象已经完成/释放,只是您正在使用的引用为null。 GC可能需要一些时间来实际释放对象。