1

假设我有 -

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会发生什么,如果它在someMethod(5000)B 内部并等待锁定,并且 Thread2 已使 B 的对象为空?我不确定 Thread1 是否会抛出哪个异常..有什么帮助吗?

4

2 回答 2

3

第二个线程持有对正在运行其方法的对象的引用(否则它将无法运行其实例方法),因此 GC 无法处理该对象,因此不会出现异常。

为了更明确地使用您的代码,当您这样做时

t.b.someMethod(5000)

JVM在内部处理t.b表达式(这是对对象的引用),所以引用计数不为0。

于 2012-12-16T13:34:28.930 回答
1

总结 SJuan76 和 op 的讨论:
看起来有两个对 t 的引用,但只有一个对 b(t 内部的那个)。t 不会被释放,因为线程独立持有它。但是,b 可能会被删除(取决于 gc),因为一旦引用无效,它的引用计数将下降到零。
所以 Thread2 可能会抛出 NullPointerException。

编辑:
在 someMethod() 内部,b 对象不会被释放,因为this指针保存在堆栈上,至少使 ref 计数为 1。您可以对成员方法的每次执行都说同样的话,因为它们中的每一个都this作为参数。

请注意,尽管您收到 NullPointerException,但这并不意味着对象已经完成/释放,只是您使用的引用为空。GC 可能需要一些时间才能真正释放对象。

于 2012-12-16T16:21:04.980 回答