我知道该主题的话题已经存在,但是他们没有回答我的问题。我们有一个Thread类,它创建一个线程并运行一个任务。我们还有一个Runnable接口,它做同样的事情,此外它还提供松散的耦合,因此最好在线程上使用Runnables。那么在什么情况下我们在Runnable上使用Threads?
是否有任何方案可以更好地使用Thread over 可以跑吗这就是我要问的。
答案 0 :(得分:1)
由于Java不支持多重继承(钻石问题等),因此Runnable提供了Threads的替代方法。当一个线程类被扩展时,那么我们就不能扩展任何其他类。
创建的每个线程对象都使一个与之关联的唯一对象。
实现Runnable时,我们可以扩展其他类,并且每个实例将同一对象共享给多个线程。
您还应该查看 Callables 和 FutureTasks 。 (“可取消的异步计算”)。这些中提供了超时,取消和线程池,并提供了比通用线程更好的替代方法。
答案 1 :(得分:1)
正如您已经描述的,有两种方法可以在不同的线程中运行代码:
Runnable
对象提供Thread
Thread
让我们看看Java的制造者在什么时候使用什么(Defining and Starting a Thread)时要说些什么:
您应该使用其中哪些惯用语?
采用
Runnable
对象的第一个习惯用法较为笼统,因为Runnable
对象可以将Thread
以外的其他类作为子类。第二个习惯用法(子类化
Thread
) 更易于在简单的应用程序中使用,但是受限于您的任务类必须是后代的事实Thread
中的。本课重点讨论第一种方法,该方法将Runnable
任务与执行该任务的Thread对象分开。这种方法不仅更加灵活,而且适用于稍后介绍的高级线程管理API。
尽管说Thread
的子类在简单的应用程序中更容易使用,但我倾向于说没有一种场景可以比提供Thread
更好地扩展Runnable
。
由于我们现在已经对Java 8提供了lambda支持,所以即使从行数的角度来看,提供Runnable
也比使用子类方法更容易:
Thread subclassingThread = new Thread() {
public void run() {
System.out.println("Subclassing Thread");
}
};
Thread providingRunnable = new Thread(() -> {
System.out.println("Providing Runnable");
});
答案 2 :(得分:1)
如果您问“是否存在使用Thread而不是Runnable来使逻辑异步运行的方案”,那么答案几乎总是“否”。
Runnable
(类似地,Callable
)代表要执行的“动作”。牢记单一责任原则,您几乎永远都不应拥有一个代表既要执行的动作(即Runnable
)和执行该动作的结构({{1} }等。
可能只有当您需要实现某种“执行器”时才需要使用Thread
,而您需要Thread
来提供一些额外的功能。除此之外,我真的看不到您想通过扩展并覆盖其Thread
Thread
的任何原因。
答案 3 :(得分:0)
您想要在可运行对象上使用线程的一个实例是您想要单独的执行线程。
public static void main(String[] args){
Runnable r = ()->{
try{
Thread.sleep(500);
System.out.println("ran!");
} catch(Exception e){ return;}
}
r.run();
System.out.println("finishing main.");
}
在这种情况下,输出将是。
跑了!
修饰主体。
如果使用新线程,则不会占用主线程。
public static void main(String[] args){
Runnable r = ()->{
try{
Thread.sleep(500);
System.out.println("ran!");
} catch(Exception e){ return;}
}
new Thread(r).start();
System.out.println("finishing main.");
}
现在输出将是:
修饰主体。
跑了!
这是因为我们启动了一个新的执行线程。 java.util.concurrent包中有一些工具可以管理并行执行。区分线程和任务/作业/可运行的概念在某种程度上很重要。