"java.lang.OutOfMemoryError: unable to create new native thread" when using Thread.sleep(..)

"java.lang.OutOfMemoryError: unable to create new native thread" when using Thread.sleep(..)

我编写了一个简单的代码来模拟我在使用 ExecuterService 生成多个线程进行负载测试时遇到的问题。

代码:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class TestThreads {

   public static void main(String[] args) {
     class Testing implements Runnable {

        @Override
        public void run() {
            Runnable r = new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(5000);
                    } catch(InterruptedException e1) {
                        Thread.currentThread().interrupt();
                    }
                    System.out.println("Running the inner thread");
                }
            };
            Thread t = new Thread(r);
            t.start(); 
            System.out.println("After the thread has been started");
        }

    };         
    ExecutorService execService = Executors.newFixedThreadPool(20);
    for (int i = 0; i < 1000000; i++) {
        Testing testing = new Testing();
        execService.execute(testing);
    }
    execService.shutdown();
    try {
        execService.awaitTermination(1000, TimeUnit.MICROSECONDS);
    } catch(InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
 }
}

当我 运行 代码时,我得到多个 java.lang.OutOfMemoryError: unable to create new native thread 异常。如果我从测试 class 的 运行 方法中删除 Thread.sleep(5000),问题就会解决。我想知道为什么会这样?当池中的线程进入休眠状态时,ExecutorService 的行为如何(是否向池中添加另一个线程)?

现在,您的线程池创建的每个线程都会调用 运行 函数。每个 运行 您还创建了一个额外的新线程。因此,您将有 20 个活动线程 + 每个已经 运行 的线程有 1 个线程,并且这些内部线程没有使用线程池来帮助清理资源。

如果您不通过删除

创建内线程,则此代码应该有效
Thread t = new Thread(r);
t.start();

您只需使用 ExecutorService 管理 Testing 运行nable,这可确保一次只有 20 个 Testing 实例处于 运行ning 状态。这些线程完成得非常快,因为它们所做的只是用 Runnable 的匿名子类 TestThreads 启动另一个线程,然后退出。

您会在控制台中看到一百万行 "After the thread has been started",表明 for 循环已完成, 然后大约 5 秒后,您会看到一百万行 "Running the inner thread" 指示嵌套线程已完成,如果 您的系统允许 运行 一百万个线程。

因此,您要限制的只是新线程的启动速率,而不是线程数。

默认情况下,每个线程获得 512kb 的堆栈(您可以使用 -Xss 命令行选项将其更改为 java)。
对于一百万个线程,这意味着您需要 1000000 * 512kb = 448Gb RAM。