processing/processing4

nf/nfc do not seem to be threadsafe and throw NullPointerException

Open

#984 opened on Mar 19, 2025

View on GitHub
 (4 comments) (0 reactions) (0 assignees)Java (176 forks)auto 404
bughelp wanted

Repository metrics

Stars
 (439 stars)
PR merge metrics
 (PR metrics pending)

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)

  1. Run this method within a thread thread("myFunction").

  2. 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