为什么创建一个线程消耗会很高?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (50)

Java教程说,创建线程消耗很高。但为什么呢?

提问于
用户回答回答于

Java线程的创建成本很高,因为需要进行大量的工作:

  • 必须为线程堆栈分配和初始化大量内存块。
  • 需要进行系统调用,以便在主机OS中创建/注册本机线程。
  • 描述符需要创建、初始化并添加到JVM内部数据结构中。

从某种意义上说,线程绑定资源的代价也很高;例如,线程堆栈、从堆栈可以访问的任何对象、JVM线程描述符、OS本机线程描述符。

用户回答回答于

其他人讨论了线程的成本来源。这个答案涵盖了为什么创建线程与许多操作相比并不那么昂贵,但是相对与任务执行替代方案相比,这是非常昂贵的相对更便宜。

The most obvious alternative to running a task in another thread is to run the task in the same thread. This is difficult to grasp for those assuming that more threads are always better. The logic is that if the overhead of adding the task to another thread is greater than the time you save, it can be faster to perform the task in the current thread.

另一种选择是使用线程池。线程池可以更高效,原因有两个:

1)重用已经创建的线程。

2)您可以调优/控制线程数,以确保您具有最佳性能。

以下程序打印:

Time for a task to complete in a new Thread 71.3 us
Time for a task to complete in a thread pool 0.39 us
Time for a task to complete in the same thread 0.08 us
Time for a task to complete in a new Thread 65.4 us
Time for a task to complete in a thread pool 0.37 us
Time for a task to complete in the same thread 0.08 us
Time for a task to complete in a new Thread 61.4 us
Time for a task to complete in a thread pool 0.38 us
Time for a task to complete in the same thread 0.08 us

这是对一个琐碎任务的测试,它公开了每个线程选项的开销。

final BlockingQueue<Integer> queue = new LinkedBlockingQueue<Integer>();
Runnable task = new Runnable() {
    @Override
    public void run() {
        queue.add(1);
    }
};

for (int t = 0; t < 3; t++) {
    {
        long start = System.nanoTime();
        int runs = 20000;
        for (int i = 0; i < runs; i++)
            new Thread(task).start();
        for (int i = 0; i < runs; i++)
            queue.take();
        long time = System.nanoTime() - start;
        System.out.printf("Time for a task to complete in a new Thread %.1f us%n", time / runs / 1000.0);
    }
    {
        int threads = Runtime.getRuntime().availableProcessors();
        ExecutorService es = Executors.newFixedThreadPool(threads);
        long start = System.nanoTime();
        int runs = 200000;
        for (int i = 0; i < runs; i++)
            es.execute(task);
        for (int i = 0; i < runs; i++)
            queue.take();
        long time = System.nanoTime() - start;
        System.out.printf("Time for a task to complete in a thread pool %.2f us%n", time / runs / 1000.0);
        es.shutdown();
    }
    {
        long start = System.nanoTime();
        int runs = 200000;
        for (int i = 0; i < runs; i++)
            task.run();
        for (int i = 0; i < runs; i++)
            queue.take();
        long time = System.nanoTime() - start;
        System.out.printf("Time for a task to complete in the same thread %.2f us%n", time / runs / 1000.0);
    }
}
}

创建一个新线程只需花费70 s。在许多(如果不是大多数)用例中,这可以被认为是微不足道的。相对地说,它比其他选项更昂贵,在某些情况下,线程池或根本不使用线程是一个更好的解决方案。

扫码关注云+社区