英文:
Problems when using threads in IJava at Jupyter notebooks
问题
我需要解释一些关于Java中线程和并发的概念,我认为在Jupyter笔记本中使用IJava内核是编写讲义的一个好方法。
但是,在笔记本中使用线程的第一个代码产生了不正确的结果。
代码如下:
Runnable r = () -> {
for (int x = 1; x < 6; x++) {
System.out.println("Runnable running " + x);
}
};
Thread t = new Thread(r);
t.start();
期望的结果是:
Runnable running 1
Runnable running 2
Runnable running 3
Runnable running 4
Runnable running 5
但在笔记本中获得的结果是:
不确定发生了什么,以及为什么没有打印出其他x值。
作为对比,我在IDE中运行代码,它按预期工作。
有关为什么它不起作用的一些想法吗?
我还尝试在println后添加了一些t.sleep(1000)
,但没有成功。
自2019年以来,IJava是否是可靠的内核?
注意:我没有翻译代码部分。
英文:
I need to explain some concepts relating Threads and concurrency in Java, and I thought that using an IJava kernel in Jupyter notebooks would be a good approach to write the lecture notes.
But the very first code using threads in the notebook yield an incorrect result.
The code is the following:
Runnable r = () -> {
for (int x = 1; x <6; x++) {
System.out.println("Runnable running " + x);
}
};
Thread t = new Thread(r);
t.start();
And the expected result is:
Runnable running 1
Runnable running 2
Runnable running 3
Runnable running 4
Runnable running 5
But what I obtain in the notebook is:
Not sure what happens here and why the rest of the x values are not printed.
As a comparison, I run the code in an IDE and it works as expected.
Some idea of why it is not working?
I also tried to add some t.sleep(1000)
after the println but to no avail.
Is IJava a reliable kernel, since it has not been updated since 2019?
答案1
得分: 1
I'm not in a position to confirm this, but from what I can tell, IJava is based on JShell rather than native Java. What I think is happening is that JShell is peremptorily closing when your main
method ends. But the main
method ends before the child thread has finished. Try adding a t.join()
call after t.start()
. That will cause main
to pause until the child thread has terminated.
Note that this doesn't happen when using a native JVM. The (normal) termination condition for a JVM is that all non-daemon threads have terminated. Your child thread isn't a daemon thread, so the JVM waits until it finishes... after your main thread finishes.
Is IJava a reliable kernel, since it has not been updated since 2019?
我不清楚。试试查找并查看该项目的问题跟踪器。
英文:
I'm not in position to confirm this, but from what I can tell IJava is based on JShell rather than native Java. What I think is happening is that JShell is peremptorily closing when your main
method ends. But the main
method ends before the child thread has finished. Try adding a t.join()
call after t.start()
. That will cause main
to pause until the child thread has terminated.
Note that this doesn't happen when using a native JVM. The (normal) termination condition for a JVM is that all non-daemon threads have terminated. Your child thread isn't a daemon thread so the JVM waits until it finishes ... after your main thread finishes.
> Is IJava a reliable kernel, since it has not been updated since 2019?
I have no idea. Try finding and looking at the issue tracker for the project.
答案2
得分: 1
代码部分不翻译,以下是翻译好的部分:
"The problem is with a background thread writing io. To try and associate it with the correct cell, the io streams are tied to the currently executing cell. When nothing is in progress the output is dropped.
To rework your example a bit, one option is to just wait for the thread to finish executing:
The above prints what you'd expect:
The way the jupyter architecture is structured, a kernel and frontend are separate. Logically there can even be multiple frontends sharing the same kernel so it isn't as straightforward to push background output from the kernel. Possible that IJava should just keep sending output to the last executed cell but I vaguely remember something along the lines of the spec not promising that frontends will continue accepting input from those streams after a cell is finished executing. (I think classic notebook does but colab doesn't, for example).
So to sum things up, threads and background threads should work fine, the io is the issue. If you have other methods of seeing the behavior of that (changing a variable, writing to a file, etc. you should be able to observe that."
英文:
The problem is with a background thread writing io. To try and associate it with the correct cell, the io streams are tied to the currently executing cell. When nothing is in progress the output is dropped.
To rework your example a bit, one option is to just wait for the thread to finish executing:
Runnable r = () -> {
for (int x = 1; x <6; x++) {
System.out.println("Runnable running " + x);
}
};
Thread t = new Thread(r);
t.start();
t.join();
The above prints what you'd expect:
Runnable running 1
Runnable running 2
Runnable running 3
Runnable running 4
Runnable running 5
The way the jupyter architecture is structured, a kernel and frontend are separate. Logically there can even be multiple frontends sharing the same kernel so it isn't as straight forward to push background output from the kernel. Possible that IJava should just keep sending output to the last executed cell but I vaguely remember something along the lines of the spec not promising that frontends will continue accepting input from those streams after a cell is finished executing. (I think classic notebook does but colab doesn't for example).
So to sum things up, threads and background threads should work fine, the io is the issue. If you have other methods of seeing the behavior of that (changing a variable, writing to a file, etc. you should be able to observe that).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论