Thursday, February 23, 2023

A Case for Zip

 I found this Python code in our project:

data = {...}
devices = get_devices()
if len(devices) > 0:
    data["first_device"] = devices[0]
if len(devices) > 1:
    data["second_device"] = devices[1]
if len(devices) > 2:
    data["third_device"] = devices[2]
if len(devices) > 3:
    data["fourth_device"] = devices[3]
if len(devices) > 4:
    data["fifth_device"] = devices[4]

It retrieves a bunch of devices, and adds them to an existing dict. I removed this code and replaced it with this one:

data = {...}
devices = get_devices()
labels = ["first_device", "second_device", "third_device", "fourth_device", "fifth_device"]
data.update(dict(zip(labels, devices)))

It takes advantage of two characteristics of the zipped list:

  1. It iterates up to the length of the shortest list.
  2. Two zipped lists can easily be turned into a dict.

Thursday, February 9, 2023

Print All JVM Flags

This article was originally posted on JRoller on the October 22nd, 2011

 I just discovered this very interesting post by Zahid Qureshi. He tells us about a JVM flag, that I never heard about before, that displays all the JVM flags, their default value, and the values that were set by your own settings. With the following line, you get a list of over 700 flags in the JDK6:

java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal -version

The "-version" flag is just here to avoid an error message. The "UnlockDiagnosticVMOptions" unlocks several JVM options.

I tried it with the JDK7, to confirm that G1 GC is not triggered by default:

bool UseG1GC = false

 These flags still exist in current Java versions, although the value of the UseG1GC flag is now set to true by default. Also, in the original comments, someone posted another flag that unlocks even more options: "-XX:+UnlockExperimentalVMOptions".

Monday, February 6, 2023

SwingWorker is not a Thread

 This article was originally posted on October 5th, 2011 on JRoller.com.

One practical class when developing Swing application is the SwingWorker. It allows you to start a lengthy task in the background, and then applying the result to the display on the Event Thread. The usual pattern is the following:

class MySwingWorker extends SwingWorker {
  @Override
  public Void doInBackground() {
    //perform background work
  }
 
  @Override
  protected void done() {
    //update display
  }
}


While the background work might be long, it is possible also to update the user interface with partial results. In which case, the pattern is the following:

class MySwingWorker extends SwingWorker<Void, Integer> {
  @Override
  public Void doInBackground() {
    while (!finished) {
      //perform background work
      publish(partialResult)
    }
    return result;
  }
 
  @Override
  protected void process(List<Integer> chunks) {
    //update display with partial results
  }
}


This seemed so practical for me, that I decided to use this instead of one of our Threads that is running in the background, waiting for some data, processing it, then adding one or several lines to a JTable. The idea would be to have my SwingWorker running constantly in the background, waiting for data from a blocking queue, then publishing the result to the Swing updating part. It looked like this:

class MyEternalSwingWorker extends SwingWorker {
  @Override
  public Void doInBackground() {
    while (!isCancelled()) {
      queue.take();
      //perform background work
      publish(row)
    }
    return null;
  }
 
  @Override
  protected void process(List chunks) {
    //add rows to the JTable
  }
}

If data were to arrive too fast, Swing has the possibility to coalesce all the updates, which should bring better performance. It worked quite fine, but suddenly, some of the users started to have some strange behaviors, and updates stopped quite unexpectedly for some windows. As it appears, it depends on the number of windows opened, and so on the number of such SwingWorkers running. That is when I discovered this interesting line in the SwingWorker code:

  private static final int MAX_WORKER_THREADS = 10;

SwingWorker is using a Thread Pool, with 10 Threads, and there is no way to change that. So all my nice Eternal Swing Workers were just using all the available Threads in the Pool, and no other Worker could start their background work.

So beware, SwingWorkers can not be used as Threads. They need to be used for finite work. Or be less than 10.

Update: As Eugene Ho suggested in the comments, SwingWorker is actually a Runnable. So you can run it in your own Thread without blocking anything in the SwingWorker's ThreadPool, while keeping all the advantages, such as events coalescing, of the class.

Update 2: Also, the number of Threads in the pool is a constant, but it is possible to override it with your own Thread Pool, since SwingWorker use the sun.awt.AppContext class to fetch it. Do the following:

  sun.awt.AppContext.getAppContext().put(SwingWorker.class, myThreadPoolExecutor);

Seeing the updates on my article, I can see that it is a pity that I could not retrieve the original comments, like the one from Eugene Ho. However, I checked the SwingWorker code, and all this is still true.