Java:多线程访问主线程变量/方法

3
我正在测试以下代码,我想知道为什么线程可以访问增量方法?
我在想,由于thread1和thread2是从匿名类创建的对象,并没有继承worker类,它们如何访问increment()方法?背后的理论是什么?
public class Worker {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public void run() {
        Thread thread1 = new Thread(new Runnable() {
            public void run() {
                for(int i = 0; i < 10000; i++) {
                    increment();
                }
            }
        });
        thread1.start();

        Thread thread2 = new Thread(new Runnable() {
            public void run() {
                for(int i = 0; i < 10000; i++) {
                    increment();
                }
            }
        });
        thread2.start();

        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        System.out.println("Count is: " + count);
    }
}

4
匿名类具有对其封闭类的引用。 - assylias
5个回答

4

由于Runnable是非静态内部类,因此Worker.this被隐式地继承到Runnable实例中。因此,真正发生的情况是:

public void run(){
   Worker.this.increment();
}

如果这个类是静态的,那么情况就不同了。

3

Java语言规范(JLS)对内部类和封闭实例有以下说明:

内部类包括局部类(§14.3)、匿名类(§15.9.5)和非静态成员类(§8.5)。

关于内部类和封闭实例,JLS指出:

如果O是C的直接词法封闭类且C的声明不在静态上下文中,则内部类C是类O的直接内部类。

最后,关于限定的this, JLS提到:

任何词法封闭的实例(§8.1.3)都可以通过显式限定关键字“this”来引用。假设C是由ClassName表示的类。令n为整数,使得C是出现在限定this表达式中的类的第n个词法封闭类。形式为ClassName.this的表达式的值是this的第n个词法封闭实例。这就是为什么您可以访问Worker的成员。调用
new Runnable()

Worker实例方法内,创建一个内部类用于Worker。因此,Worker是该Runnable的第0个词法封闭类。关于上述JLS引用,请将ClassName替换为Worker,然后您就可以访问您的方法。

Worker.this.increment()

这是由编译器隐式完成的


1
一个匿名内部类可以访问封闭类实例的字段和方法。简而言之,每个内部类的实例都保留对封闭类的引用,以便能够访问其字段。如果您想了解有关内部类、静态类等的更多信息,请查看该主题(嵌套类)上的Java教程http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html。此外,请确保理解与非静态内部类相关的危险,因为它们可能会在将内部实例的引用交给封闭类外的代码时造成麻烦并导致内存泄漏。

0

因为它是一个非静态内部类,所以它会捕获对创建它的Worker实例的引用。这意味着您可以在匿名类中调用worker的方法。


0

“理论”在内部类中有所描述。实践是,内部类构造函数具有指向外部类实例的隐藏参数,并且该参数保存在隐藏字段中。可以使用Worker.this结构从内部类方法中访问此字段。


这意味着匿名类始终被视为内部类吗? - Carlo Luther
1
是的,JLS明确指出“内部类包括局部、匿名和非静态成员类”。 - Alexei Kaigorodov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接