Turtlegraphics with Java
HomeAufgabenDruckenJava-Online

Threads

According to von Neumann's principle, a computer is basically a sequential machine, i.e. a programme is processed instruction by instruction. This model no longer fulfils today's requirements. Today's operating systems run several programmes in parallel (multitasking). As only one processor is available, this is achieved by fast switching between the processes. Resources are released to the individual programmes for a certain period of time (unlocked) and then locked later.

Parts of a single Java programme can also be divided between several processes, which are referred to as threads.

Without using threads two Turtles cannot run at the same time. They each draw one step in turn.


// WithoutThread.java

import ch.aplu.turtle.*;
import java.awt.Color;

public class WithoutThread
{
  public WithoutThread()
  {
    Turtle john = new Turtle()
    Turtle laura = new Turtle(john)
    laura.setColor(Color.red);
    laura.setPenColor(Color.red);
    laura.setPos(0160);
    laura.left(90);
    for (int i = 0; i < 8; i++)
    {
      step(john);
      step(laura);
    }  
  } 
  
  private void step(Turtle t)
  {
    t.forward(20);
    t.left(90);
    t.forward(20);
    t.right(90);
  } 

  public static void main(String[] args)
  {
    new WithoutThread();
  }
}
 


Using threads the two turtles can run simultaneously. To do this, declare an (inner) class JohnThread that is derived from Thread and overwrite the method run(). The thread is started by creating an instance of this class and calling the start() method. The JRE then executes the run() method in a separate thread (the run() method must never be called by the user).

// ThreadEx1.java

import ch.aplu.turtle.*;
import java.awt.Color;

public class ThreadEx1 extends TurtleFrame
{
  public ThreadEx1()
  {
    Turtle john = new Turtle(this);
    Turtle laura = new Turtle(this);
    laura.setColor(Color.red);
    laura.setPenColor(Color.red);
    laura.setPos(0, 160);
    laura.left(90);
    draw(john);
    draw(laura);
  }

  private void draw(final Turtle t)
  {
    new Thread()
    {
      public void run()
      {
        for (int = 0; i < 8; i++)
          step(t);
      }
    }.start();
  }


  private void step(Turtle t)
  {
    t.forward(20);
    t.left(90);
    t.forward(20);
    t.right(90);
  }

  public static void main(String[] args)
  {
    new ThreadEx1();
  }
}
   


Explanations of the programme code:
On closer inspection, you can see that the two Turtles are not moved simultaneously (there is no real parallel execution). On the other hand, the threads are also interrupted within the forward and rotational movement.

 

Example 2:
Declaring two classes with practically the same code is a little unsightly. You can avoid this code duplication by declaring a single Animator class to which the turtle reference to be moved is passed in the constructor.

// ThreadEx2.java

import ch.aplu.turtle.*;
import java.awt.Color;

public class ThreadEx2 extends TurtleFrame
{
  public ThreadEx2()
  {
    Turtle john = new Turtle(this);
    Turtle laura = new Turtle(thisColor.red);
    Turtle sara = new Turtle(thisColor.green);
    john.setPos(-100-100);
    laura.setPos(-20-100);
    sara.setPos(60, -100);
    laura.setPenColor(Color.red);
    sara.setPenColor(Color.green);
    draw(john);
    draw(laura);
    draw(sara);
  }

  private void draw(final Turtle t)
  {
    new Thread()
    {
      public void run()
      {
        for (int = 0; i < 5; i++)
          square(t);
      }
    }.start();
  }

  private void square(Turtle t)
  {
    for (int i = 0; i < 4; i++)
      t.forward(40).right(90);
    t.forward(40);
  }

  public static void main(String[] args)
  {
    new ThreadEx2();
  }

}
   

Explanations of the programme code:
new Animator(john).start() To simplify matters, an anonymous class is created and its start() method is called

 

Examople 3:
The next example shows that the arbitrary interruption of the application thread, which lets the turtle draw a square, by a mouse click that sets the turtle to a new starting position, leads to a mess. (The callback method mousePressed() is executed in the so-called Event Dispatch Thread (EDT)).


// ThreadEx3.java

import ch.aplu.turtle.*;
import java.awt.Color;

public class ThreadEx3 extends TurtleFrame
{
  public ThreadEx3()
  {
    Turtle john = new Turtle(this);
    Turtle laura = new Turtle(thisColor.red);
    Turtle sara = new Turtle(thisColor.green);
    john.setPos(-135-50);
    laura.setPos(-10-50);
    sara.setPos(115, -50);
    laura.setPenColor(Color.red);
    sara.setPenColor(Color.green);
    new TurtleThread(john).start();
    new TurtleThread(laura).start();
    new TurtleThread(sara).start();
  }

  private class TurtleThread extends Thread
  {
    private Turtle turtle;

    private TurtleThread(Turtle turtle)
    {
      this.turtle = turtle;
    }

    public void run()
    {
      for (int = 0; i < 9; i++)
        segment(turtle);
    }
  }

  private void segment(Turtle t)
  {
    t.forward(140);
    t.right(160);
  }

  public static void main(String[] args)
  {
    new ThreadEx3();
  }
}
   

Explanations of the programme code:
addMouseListener(new MyMouseAdapter()) A separate mouse adapter is used

 

Example 4:
To bring order to the confusion, the two threads, the application thread and the EDT, must be synchronised. The Java monitor concept is used for this: Each object has a "lock" (also called a monitor). When entering a block designated with synchronised(), the thread requests the lock. If this is not already assigned to another thread, it is handed over. At the end of the block, the thread returns the lock. Other threads that want to enter the block during this time must wait for the lock.


// ThreadEx4.java

import ch.aplu.turtle.*;
import java.awt.event.*;

public class ThreadEx4
{
  public ThreadEx4()
  {
    final Turtle joe = new Turtle();
    joe.hideTurtle();
    joe.addStatusBar(30);
    joe.setStatusText("Click to create a new turtle");
    joe.addMouseListener(new MouseAdapter()
    {
      public void mousePressed(MouseEvent e)
      {
        Turtle = new Turtle(joe);
        t.setScreenPos(e.getPoint());
        star(t);
      }
    });
  }

  private void star(final Turtle t)
  {
    new Thread()
    {
      public void run()
      {
        for (int = 0; i < 5; i++)
          t.fd(40).rt(144);
      }
    }.start();
  }

  public static void main(String[] args)
  {
    new ThreadEx4();
  }
}
   

Explanations of the programme code:

private void square()
{
   synchronized (john) .....
}

The application thread requires the lock before drawing the square

public void mousePressed(MouseEvent evt)
{
   synchronized (john)....
}

The EDT requires the lock to set the new starting point