解决 java.lang.OutOfMemoryError: unable to create new native thread
这个异常问题本质原因是我们创建了太多的线程,而能创建的线程数是有限制的,导致了异常的发生。
注意:能创建的线程数的具体计算公式如下:
(MaxProcessMemory - JVMMemory - ReservedOsMemory) / (ThreadStackSize) = Number of threads
MaxProcessMemory 指的是一个进程的最大内存 JVMMemory JVM内存 ReservedOsMemory 保留的操作系统内存 ThreadStackSize 线程栈的大小
在java语言里, 当你创建一个线程的时候,虚拟机会在JVM内存创建一个Thread对象同时创建一个操作系统线程,而这个系统线程的内存用的不是JVMMemory,而是系统中剩下的内存(MaxProcessMemory - JVMMemory - ReservedOsMemory)。
所以,由公式得出结论:你给JVM内存越多,那么你能创建的线程越少,越容易发生 java.lang.OutOfMemoryError: unable to create new native thread。
每new一个Timer会启动一个线程,如果使用在循环或者递归当中,很容易造成JVM报如下错误:
java.lang.OutOfMemoryError: unable to create new native thread
最后采用的是线程池办法Executors.newScheduledThreadPool(),避免用new Timer()
并且把改为接将这个变量改为静态变量,避免每次都初始化线程池
Timer和TimerTask的简单组合是多线程的嘛?不是,一个Timer内部包装了“一个Thread”和“一个Task”队列,这个队列按照一定的方式将任务排队处理,包含的线程在Timer的构造方法调用时被启动,这个Thread的run方法无限循环这个Task队列,若队列为空且没发生cancel操作,此时会一直等待,如果等待完成后,队列还是为空,则认为发生了cancel从而跳出死循环,结束任务;循环中如果发现任务需要执行的时间小于系统时间,则需要执行,那么根据任务的时间片从新计算下次执行时间,若时间片为0代表只执行一次,则直接移除队列即可。
Java的一个Timer对象本身只有一个线程,如果向他提交多个task,并且某个task相当耗时的话,其他的task即使到了执行时间,仍然会等之前的task执行完毕。更有问题,如果前一个task抛出了异常导致线程终止,后面的task将无法执行。
Java5以后推荐采用java.util.concurrent的ScheduledExecutorService,至少能避免异常导致线程结束的问题。 (ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1)) 如果对时间有比较准确的需要,务必一个ScheduledExecutorService处理一个任务。