processing / processing/processing4
nf/nfc do not seem to be threadsafe and throw NullPointerException
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 494
- Forks
- 183
- Avg merge
- 4h 39m
- Merged PRs (30d)
- 3
Description
Most appropriate sub-area of Processing 4?
Core/Environment/Rendering
Processing version
3 to current
Operating system
Linux
Steps to reproduce this
"1. Create a method calling nf(float, int, int), nf(int, int), nfc(float, int)
-
Run this method within a thread
thread("myFunction"). -
Let it run for a longer time"
This is a little bit harder to reproduce and I only got it first with a complex project.
After a while you will end up with either a Stackoverflow or NullPointerException like this.
java.lang.NullPointerException: Cannot assign field "fastPathContainer" because "this.fastPathData" is null
at java.base/java.text.DecimalFormat.resetFastPathData(DecimalFormat.java:1157)
at java.base/java.text.DecimalFormat.checkAndSetFastPathStatus(DecimalFormat.java:1081)
at java.base/java.text.DecimalFormat.fastFormat(DecimalFormat.java:1659)
at java.base/java.text.NumberFormat.format(NumberFormat.java:327)
at processing.core.PApplet.nf(PApplet.java:10108)
at core3.app.gui.GUIInfo.pre(GUIInfo.java:413)
at jdk.internal.reflect.GeneratedMethodAccessor24.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:569)
at processing.core.PApplet$RegisteredMethods.handle(PApplet.java:1436)
at processing.core.PApplet$RegisteredMethods.handle(PApplet.java:1429)
at processing.core.PApplet.handleMethods(PApplet.java:1628)
at processing.core.PApplet.handleDraw(PApplet.java:2473)
at processing.opengl.PSurfaceJOGL$DrawListener.display(PSurfaceJOGL.java:866)
at jogamp.opengl.GLDrawableHelper.displayImpl(GLDrawableHelper.java:692)
at jogamp.opengl.GLDrawableHelper.display(GLDrawableHelper.java:674)
at jogamp.opengl.GLAutoDrawableBase$2.run(GLAutoDrawableBase.java:443)
at jogamp.opengl.GLDrawableHelper.invokeGLImpl(GLDrawableHelper.java:1293)
at jogamp.opengl.GLDrawableHelper.invokeGL(GLDrawableHelper.java:1147)
at com.jogamp.newt.opengl.GLWindow.display(GLWindow.java:759)
at com.jogamp.opengl.util.AWTAnimatorImpl.display(AWTAnimatorImpl.java:81)
at com.jogamp.opengl.util.AnimatorBase.display(AnimatorBase.java:452)
at com.jogamp.opengl.util.FPSAnimator$MainTask.run(FPSAnimator.java:178)
at java.base/java.util.TimerThread.mainLoop(Timer.java:566)
at java.base/java.util.TimerThread.run(Timer.java:516)
snippet
Additional context
Doing a little bit research, the NumberFormat in nf/nfc seems not to be thread safe. General consent on this seems to be to use a ThreadLocal. So modifying PApplet like this, seems to fix it.
private static final ThreadLocal<NumberFormat> threadLocalIntNf = ThreadLocal.withInitial(() -> {
NumberFormat nf = NumberFormat.getInstance();
nf.setGroupingUsed(false); // no commas
nf.setMinimumFractionDigits(0);
nf.setMaximumFractionDigits(0);
return nf;
});
static public String nf(float num, int left, int right) {
// if ((float_nf != null) &&
// (float_nf_left == left) &&
// (float_nf_right == right) &&
// !float_nf_commas) {
// return float_nf.format(num);
// }
float_nf = threadLocalIntNf.get();
float_nf.setGroupingUsed(false);
float_nf_commas = false;
float_nf.setMinimumIntegerDigits(left);
float_nf.setMinimumFractionDigits(right);
float_nf.setMaximumFractionDigits(right);
return float_nf.format(num);
}
Would you like to work on the issue?
I can provide my fix, but it needs some optimisation/cleanup.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in processing.core.PApplet at the nf call shown in the stack trace, then inspect the related nf and nfc formatting paths and their NumberFormat state. Run the threaded reproduction with nf(float, int, int), nf(int, int), and nfc(float, int) repeatedly; done means concurrent execution no longer produces the reported NullPointerException or StackOverflow.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- api
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100