Threads, Listeners and Events
Threads, Listeners and Events

Java Threads

When a Java program starts, there is a single thread running – the main thread.

Many of the leJOS classes start extra threads running for various purposes, for example:

  • Button and SensorPort start a listener thread if listeners are used
  • NXTRegulatedMotor (and hence Motor) start a single motor regulator thread
  • The Bluetooth class starts a thread to talk to the separate Bluetooth chip
  • Each Timer object starts a timer thread
  • Some of the navigation classes, e.g. NavPathController, start extra threads

User programs can create their own threads by subclassing Thread, and then using the start method to start the thread. In leJOS NXJ 0.7 and later, threads can be created from any class that implements the Runnable interface.

Background threads that do not need to terminate in order for the user program to terminate, should be marked as daemon threads by calling setDaemon(true).

When using threads, care should be taken with concurrency issues. When data items are accessed by multiple threads, synchronization is necessary to ensure that data is not read when it is in an inconsistent state.

leJOS NXJ supports the standard Java synchronization mechanisms: synchronized methods and synchronized statements using a monitor object.

As an example of a leJOS thread, consider the Indicators thread in the leJOS StartUpText menu. This is used to keep the display of the battery level up to date, by reading its value every second, and to indicate when the menu is uploading files or doing other communication from the PC:

import lejos.nxt.LCD;

class Indicators extends Thread {
  private boolean io = false;

  public void ioActive() {
    io = true;
  }

  public void run() {
    String[] ioProgress = { ".   ", " .  ", "  . " };
    int ioIndex = 0;
    boolean rewrite = false;
    while (true) {
      try {
        if (io) {
          StartUpText.g.drawString("     ", 76, 0);
          ioIndex = (ioIndex + 1) % ioProgress.length;
          StartUpText.g.drawString(ioProgress[ioIndex], 78, 0);
          io = false;
          rewrite = true;
        } else if (rewrite) {
          LCD.drawString("   ", 13, 0);
          // invert when power is off
          StartUpText.g.drawString(" BT", 82, 0, !StartUpText.btPowerOn);
          StartUpText.g.refresh();
          rewrite = false;
        }
        Thread.sleep(1000);
      } catch (InterruptedException ie) {
      }
    }
  }
}

The main method starts this thread by:

Indicators ind = new Indicators();
ind.setDaemon(true);	
ind.start();

Back to top

Listeners and Events

leJOS implements a listener thread that listens for particular events.

The listener thread supports:

  • Button Listeners
  • Sensor Port Listeners

Button listeners are used to detect when a button is pressed, whatever your program is doing at the time.

To listen for a press of a specific button, you register as listener for that button.

Example:

import lejos.nxt.Button;
import lejos.nxt.ButtonListener;
import lejos.nxt.LCD;

public class ListenForButtons {
  public static void main(String[] args) throws Exception {
    Button.ENTER.addButtonListener(new ButtonListener() {
      public void buttonPressed(Button b) {
        LCD.drawString("ENTER pressed", 0, 0);
      }

      public void buttonReleased(Button b) {
        LCD.clear();
      }
    });

    Button.ESCAPE.waitForPressAndRelease();
  }
}

Back to top