我编写了一个简单的代码来模拟我使用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的行为如何(它是否将另一个线程添加到池中)?
答案 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。