我有下一个任务
public class QuittableTask implements Runnable {
final int id;
public QuittableTask(int id) {
this.id = id;
}
private AtomicBoolean running = new AtomicBoolean(true);
public void quit() {
System.out.println("Quite " + Thread.currentThread().getName());
running.set(false);
}
@Override
public void run() {
while (running.get()) {
System.out.println(Thread.currentThread().getName());
new Nap(0.1);
}
System.out.print(id + " ");
}
我使用运行许多任务
public class QuittingTasks {
public static final int COUNT = 1500;
public static void main(String[] args) throws InterruptedException {
ExecutorService es = Executors.newCachedThreadPool();
List<QuittableTask> tasks =
IntStream.range(1, COUNT)
.mapToObj(QuittableTask::new)
.peek(es::execute)
.collect(Collectors.toList());
Thread.currentThread().sleep(1000);
tasks.forEach(QuittableTask::quit);
es.shutdown();
}
当我使用 COUNT <10000 时,一切正常。所有线程都将终止。编程在2秒内完成。
但是当我使用 COUNT> 100001 方法时,无法达到相当的方法,并且我的程序将进入无限循环。我不明白这种行为。有人可以向我解释吗?
答案 0 :(得分:3)
如果仔细查看日志(在代码上添加一些日志),则可以在程序生成OutOfMemoryError
时看到。该错误如下所示:
java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:717)
at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:957)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1378)
at java.util.stream.ReferencePipeline$11$1.accept(ReferencePipeline.java:372)
at java.util.stream.IntPipeline$4$1.accept(IntPipeline.java:250)
at java.util.stream.Streams$RangeIntSpliterator.forEachRemaining(Streams.java:110)
at java.util.Spliterator$OfInt.forEachRemaining(Spliterator.java:693)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
at com.java8.demo.Main.main(Main.java:58)
这意味着当您尝试在所有任务上调用quit
时,您将获得OutOfMemory,但是由于发生错误而永远不会执行该错误,因为布尔标志永远不会设置为false。其他线程继续运行。
您会注意到内存不足是因为VM无法创建本机线程。现在您正在使用Executors.newCachedThreadPool();
。因此您的线程池最大大小可以为Integer.MAX_VALUE
,但在达到该值之前,您的VM无法创建新线程。我已将执行程序更改为Fix ExecutorService es = Executors.newFixedThreadPool(8);
到FixTheradPool。当您创建更高的COUNT
值时,它可以正常工作,因为它将仅创建8个线程。
我放置了一个try-catch
块来跟踪如下所示的异常。另外,我通过调用System#exit在控制台上跟踪日志来强制退出VM。
try {
ExecutorService es = Executors.newCachedThreadPool();
List<QuittableTask> tasks = IntStream.range(1, COUNT).mapToObj(QuittableTask::new).peek(es::execute)
.collect(Collectors.toList());
Thread.currentThread().sleep(1000);
tasks.forEach(QuittableTask::quit);
es.shutdown();
} catch (Throwable e) {
System.out.println("Error" + e.getMessage());
e.printStackTrace();
System.exit(0);
}
答案 1 :(得分:2)
要添加到@AmitBera的答案中-Executors.newCachedThreadPool()
创建了一个几乎不受限制的线程池(请参阅the API doc中“排队”部分的说明)。因此,每个新的QuittingTask
实例都会移交给新线程并立即执行。
在某些时候,QuittingTask
实例和新线程实例(尤其是新线程实例)的数量会耗尽内存。这个“点”对JVM的内存配置很敏感。您碰巧获得了10001。运行此程序时,我用了4073。