从我在Java中使用线程的时间来看,我发现了两种编写线程的方法:

使用可运行的机具:

public class MyRunnable implements Runnable {
    public void run() {
        //Code
    }
}
//Started with a "new Thread(new MyRunnable()).start()" call

或者,使用扩展线程:

public class MyThread extends Thread {
    public MyThread() {
        super("MyThread");
    }
    public void run() {
        //Code
    }
}
//Started with a "new MyThread().start()" call

这两个代码块有什么显著的区别吗?


当前回答

我想说还有第三种方法:

public class Something {

    public void justAnotherMethod() { ... }

}

new Thread(new Runnable() {
   public void run() {
    instanceOfSomething.justAnotherMethod();
   }
}).start();

也许这受到了我最近大量使用Javascript和Actionscript 3的影响,但是这样你的类就不需要实现一个非常模糊的接口,比如Runnable。

其他回答

您应该实现Runnable,但如果您在Java5或更高版本上运行,则不应该使用新线程启动它,而是使用ExecutorService。有关详细信息,请参阅:如何在Java中实现简单线程。

线程保持不打算访问的行为;

它的同步锁用于连接等。它有一些你可以偶然访问的方法。

但是,如果您的子类Thread必须考虑实现更多Thread。

public class ThreadMain {
    public int getId() {
        return 12345678;
    }

    public String getName() {
        return "Hello World";
    }

    public String getState() {
        return "testing";
    }

    public void example() {
        new Thread() {
            @Override
            public void run() {
                System.out.println("id: "+getId()+", name: "+getName()+", state: "+getState());
            }
        }.start();
    }

    public static void main(String[] args) {
        new ThreadMain().example();
    }
}

如果你运行这个,你可能会期望

id: 12345678, name: Hello World, state: testing

然而,您并没有调用您认为是的方法,因为您使用的是Thread而不是ThreadMain中的方法,相反,您会看到类似

id: 11, name: Thread-0, state: RUNNABLE

我会说实际任务与线程分离。在Runnable的情况下,我们可以将任务传递给线程、执行器框架等,而通过扩展Thread任务则与线程对象本身耦合。在扩展线程的情况下,无法执行任务隔离。这就像我们将任务烧成线程对象,就像IC芯片一样(更具体地说,不会得到任务的任何句柄)。

我不是专家,但我能想到实现Runnable而不是扩展Thread的一个原因:Java只支持单一继承,因此只能扩展一个类。

编辑:这原本是说“实现一个接口需要更少的资源”,但无论如何都需要创建一个新的线程实例,所以这是错误的。

通过扩展线程类,派生类不能扩展任何其他基类,因为java只允许单一继承。相反,通过实现可运行接口,类仍然扩展了其他基类。

实现Runnable和扩展Thread之间最显著的区别如下:

通过扩展Thread,派生类本身就是一个线程对象,而实现Runnable接口则将同一对象共享给多个线程。