2 回答
TA贡献1836条经验 获得超4个赞
注意:实例化一个Thread对象比实例化一个Runnable实例成本更高(资源方面)。实现Runnable过度扩展背后的想法Thread是线程重用。
从概念上讲,一个线程对象可以(同步)运行任意数量的任务(runanbles 就是这种情况)。例如,执行者会利用这一点。
Executor executor = Executors.newFixedThreadPool(10);
for(int i = 0; i < 1000; i ++ ) {
executor.execute(() -> System.out.println("test"));
}
在这种情况下,10 个线程池运行 1000 个 runanble。与扩展相关的开销会Thread增加您必须处理的任务越多(因此,尽管在您的示例中差异很小,但如果您必须运行 10000 个任务,差异将变得明显)。
因此,实施Runnable而不是扩展是一个很好的做法Thread。
TA贡献1848条经验 获得超2个赞
当你构造一个Thread
对象时,你所做的不仅仅是构造那个对象。您还可以在 JVM 中分配一个线程,它通常使用操作系统 API 来执行此操作。操作系统线程比进程便宜,但比大多数其他操作系统对象要重要得多,因为每个线程都有自己的执行上下文,需要由内核处理。此外,每个线程都有自己的执行堆栈,必须为此分配空间。在大多数 Java 实现中,与新线程相关的实际内存分配超过 1 兆字节(!)。相比之下,您Runnable
只会分配几个字节。
如果您在应用程序的整个生命周期中重复使用线程来完成工作,那么内存成本将被摊销。更重要的是,设置新线程的 CPU 时间成本非零(通常是系统调用,这意味着至少进行一次上下文切换,有时会丢失当前线程的其余部分)。与创建新线程相比,将新工作与已经运行的线程进行通信的工作量要少得多。
一个好的经验法则是想暴露并发相关机制java.lang
(Thread
,Object.wait
)作为低级别的基本操作,并在暴露的API java.util.concurrent
(Executor
,Future
,等)作为更高级别的操作。低级机制(稍微)更灵活,但也更难正确使用。高级机制同样强大,但通常允许您在更高的抽象层次上思考问题,这通常会使您的程序更清晰、更正确。
添加回答
举报