使用Thread.sleep(..)时“java.lang.OutOfMemoryError:无法创建新的本机线程”

时间:2015-11-27 23:47:56

标签: java multithreading threadpool executorservice threadpoolexecutor

我编写了一个简单的代码来模拟我使用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例外。如果我从Testing类的run方法中删除Thread.sleep(5000),问题就会解决。我想知道为什么会这样?当池中的线程进入休眠状态时,ExecutorService的行为如何(它是否将另一个线程添加到池中)?

2 个答案:

答案 0 :(得分:1)

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

如果您不通过删除

创建内部线程,则此代码应该有效
$qry = "SELECT ID FROM SharePoint001 ORDER BY DownloadedTimeStamp DESC LIMIT 1"; 
$result = mysql_query($qry); // You are missing this line

$data = array();   
while($rows = mysql_fetch_array($result)) // You have to pass result into mysql_fetch_array not query string 
{
    $data[] = array("ID" => $rows['ID']);
}
print_r(json_encode($data[0])); 

答案 1 :(得分:1)

您只能使用ExecutorService管理Testing runnable,这样可确保一次只运行20个Testing个实例。这些线程非常快速地完成,因为他们所做的就是使用名为Runnable的匿名子类TestThreads$1启动另一个线程,然后退出。

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

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

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