Java Lecture 8

[Previous Lecture] [Lecture Index]

Intro to Threads

Threads

Creating threads

  1. create a class with a
    public void run()
  2. class must either
    extend java.lang.Thread
    or
    implement java.lang.Runnable
  3. create a Thread object using this class
    For example,
        class MyThread extends Thread {
    	// ...
    	public void run() {
    	    // ...
    	}
    	// ...
        }
        // ...
    	MyThread t = new MyThread();
    
    or (the more flexible option)
        class MyClass implements Runnable {
    	// ...
    	public void run() {
    	    // ...
    	}
    	// ...
        }
        // ...
    	myClass = new MyClass();
    	// ...
    	Thread t = new Thread(myClass);
    
Once created, start the thread using
    t.start();
(thread t starts executing the run() method).

PrintApplet.java

/*
 * <applet code=PrintApplet width=400 height=200>
 * </applet>
 */
import java.awt.*;

public class PrintApplet extends java.applet.Applet
{
    private TextArea text;
    private Thread t1, t2;

    public void init() {
        text = new TextArea(10, 40);
        add(text);
        t1 = new Thread(new PrintThread("A", 1000, text));
        t2 = new Thread(new PrintThread("    B", 600, text));
        t1.start();
        t2.start();
    }
}

class PrintThread implements Runnable {
    private String name;
    private int delay;
    private TextArea ta;

    public PrintThread(String name, int delay, TextArea ta)
    {
        this.name = name;
        this.delay = delay;
        this.ta = ta;
    }
    public void run() {
        for (int i = 0; i < 10; i++) {
            ta.append(name + ": " + i + "\n");
            try {
                Thread.sleep(delay);
            } catch (InterruptedException e) {
            }
        }
        ta.append(name + ": finished" + "\n");
    }
}

Static Thread methods

Thread th = Thread.currentThread();
gets the Thread object for the thread that executes this call (the "current thread").

Thread.sleep(milliseconds);
puts the current thread to sleep for that length of time. (almost always called in a try block to catch the InterruptedException.)

Thread.yield();
lets another thread run (if there is one that can run).

normal Thread methods

void start()
starts the thread running. The run() method of the Runnable attached to the Thread is called in that thread.

void stop()
stops the thread immediately. The thread cannot be restarted.

more normal Thread methods

void suspend()
stops the thread from running, until a resume() is called.

void resume()
causes the thread to continue running from where it was suspended.

void setPriority(int prio)
changes the priority of the thread. Threads with a higher valued priority run preferentially to lower priority threads.

int getPriority()
returns the priority of the thread.

void join()
causes the current thread to wait until this thread is finished (either run() returns or the thread is stop()-ed).

Keeping your data safe

The synchronized keyword.

MovingImage.java

/*
 * <applet code=MovingImage width=400 height=400>
 * </applet>
 */
import java.awt.*;
import java.awt.event.*;

public class MovingImage extends java.applet.Applet implements Runnable
{
  public void init() {
    image = getImage(getCodeBase(), "image.gif");
    getBuffer();

    addMouseMotionListener(
        new MouseMotionAdapter() {
            public void mouseDragged(MouseEvent me) {
                calcDelta(me.getX(), me.getY());
                point = new Point(me.getX(), me.getY());
                repaint();
            }
        }
    );
  }

  public void start() {
    if (mover == null) {
        mover = new Thread(this);
        mover.start();
    }
  }

  public void stop() {
    if (mover != null) {
        mover.stop();
        mover = null;
    }
  }

  public void run() {
    while (true) {
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
        }
        moveByDelta();
        repaint();
    }
  }

  private synchronized void calcDelta(int newX, int newY)
  {
    if (point != null) {
        deltaX = newX - point.x;
        deltaY = newY - point.y;
    }
  }

  private synchronized void moveByDelta() {
    if (point != null) {
        int xNew = point.x + deltaX;
        int yNew = point.y + deltaY;

        if (xNew < 0) {
            deltaX = -deltaX;
            xNew = - xNew;
        } else if (xNew > bufferSize.width) {
            deltaX = -deltaX;
            xNew -= xNew - bufferSize.width;
        }
        if (yNew < 0) {
            deltaY = -deltaY;
            yNew = -yNew;
        } else if (yNew > bufferSize.height) {
            deltaY = -deltaY;
            yNew -= yNew - bufferSize.height;
        }
        point.x = xNew;
        point.y = yNew;
    }
  }

  public void update(Graphics g) {
    updateBuffer();
    paint(g);
  }

  public void paint(Graphics g) {
    if (!getSize().equals(bufferSize))
        getBuffer();
    g.drawImage(bufferImage, 0, 0, this);
  }

  private void getBuffer() {
    if (bufferImage != null) {
        bufferImage.flush();
        bufferImage = null;
    }
    bufferSize = getSize();
    bufferImage = createImage(bufferSize.width, bufferSize.height);
    updateBuffer();
  }

  private void updateBuffer() {
    Graphics buffer = bufferImage.getGraphics();
    buffer.clearRect(0, 0, bufferSize.width, bufferSize.height);
    if (point != null)
        buffer.drawImage(image, point.x, point.y, this);
  }

  private int deltaX, deltaY;
  private Point point;       // where to draw
  private Image image;       // what to draw
  private Image bufferImage; // what to draw on
  private Dimension bufferSize;
  private Thread mover;
}

[Previous Lecture] [Lecture Index]