views:

84

answers:

1

The code below is to emulate a robotics simulator I'm working with. I'm not entirely sure why this doesn't work - I'm not very familiar with threads and even though I've tried reading plenty today, I don't seem to be making progress. The problem is that once pauseDistanceSensor() is called, it never wakes up.

import java.util.Random;

public class TestThreads
{
    private DistanceSensor dist;
    private Thread distanceThread;
    public TestThreads()
    {
        this.dist = new DistanceSensor();
        this.distanceThread = new Thread(this.dist);
        this.distanceThread.start();
    }

    public int getDistance()
    {
        return this.dist.getMeasurement();
    }

    public void pauseDistanceSensor()
    {
        synchronized(this.dist)
        {
            try {
                this.dist.wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    public void resumeDistanceSensor()
    {
        synchronized(this.dist)
        {
            this.dist.notify();
        }
    }

    public static void main(String[] args)
    {
        TestThreads test = new TestThreads();
        long timestamp = System.currentTimeMillis();
        System.out.println("Starting at "+timestamp);
        System.out.println("1: "+test.getDistance());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("2: "+test.getDistance());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("waiting distance sensor and making 3 getDistance calls then sleeping main thread for 1 second - all 3 getDistance calls should be printed when the sleep ends");
        test.pauseDistanceSensor();
        System.out.println("3: "+test.getDistance());
        System.out.println("4: "+test.getDistance());
        System.out.println("5: "+test.getDistance());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("Alive! Notifying the thread");
        test.resumeDistanceSensor();
        System.out.println("Done at "+System.currentTimeMillis());
    }
}

class DistanceSensor implements Runnable
{
    private final Random gen = new Random(54);
    private int currentVal;
    public DistanceSensor()
    {
        this.currentVal = this.gen.nextInt(1500);
    }

    public void run()
    {
        this.currentVal = this.gen.nextInt(1500);
    }

    public int getMeasurement()
    {
        return this.currentVal;
    }
}
+4  A: 

Your call to the 'pauseDistanceSensor' blocks the main thread on the wait call.

Also your sensor run method only sets the sensor value once; the run method should loop, setting the value each time.

Your pause method should instead call a synchronized method that suspends the sensor run loop, using a boolean flag or similar.

import java.util.Random;

public class TestThreads
{
    private DistanceSensor dist;
    private Thread distanceThread;
    public TestThreads()
    {
        this.dist = new DistanceSensor();
        this.distanceThread = new Thread(this.dist);
        this.distanceThread.start();
    }

    public int getDistance()
    {
        return this.dist.getMeasurement();
    }

    public void pauseDistanceSensor()
    {
      dist.setPaused(true);
    }

    public void resumeDistanceSensor()
    {
      dist.setPaused(false);
    }

    public void finish() {
      dist.setDone();
    }

    public static void main(String[] args)
    {
        TestThreads test = new TestThreads();
        long timestamp = System.currentTimeMillis();
        System.out.println("Starting at "+timestamp);
        System.out.println("1: "+test.getDistance());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("2: "+test.getDistance());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("waiting distance sensor and making 3 getDistance calls then sleeping main thread for 1 second - all 3 getDistance calls should be printed when the sleep ends");
        test.pauseDistanceSensor();
        System.out.println("3: "+test.getDistance());
        System.out.println("4: "+test.getDistance());
        System.out.println("5: "+test.getDistance());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("Alive! Notifying the thread");
        test.resumeDistanceSensor();
        System.out.println("Done at "+System.currentTimeMillis());
        test.finish();
    }
}

class DistanceSensor implements Runnable
{
    private final Random gen = new Random(54);
    private int currentVal;
    private boolean done = false, paused = false;
    public DistanceSensor()
    {
        this.currentVal = this.gen.nextInt(1500);
    }

    public void run()
    {
        while(!getDone()) {
          if(!getPaused()) synchronized(this) {this.currentVal = this.gen.nextInt(1500);}
          synchronized(this) {
            try {
              wait(500);
            } catch(InterruptedException ex) {
              ex.printStackTrace();
            }
          }
        }
    }

    public synchronized int getMeasurement()
    {
        return this.currentVal;
    }

    public synchronized boolean getPaused() {return paused;}
    public synchronized boolean getDone() {return done;}
    public synchronized void setPaused(boolean p) {paused = p;}
    public synchronized void setDone() {done = true;notify();}
}
sje397
When I read this last night, I thought you were dead on. I ran it this morning and this is the output..Starting at 1277311524656/1: 1391/2: 475/waiting distance sensor and making 3 getDistance calls then sleeping main thread for 1 second - all 3 getDistance calls should be printed when the sleep ends/3: 114/4: 114/5: 114/Alive! Notifying the thread/Done at 1277311527716I want to have the print messages appear AFTER "Alive! Notifying the thread" by pausing the DistanceSensor's thread.
alleywayjack
You would have to move your prints into the sensor thread. Pausing the sensor won't pause the main thread where the prints are bing done - and if it did, the print calls won't be made until the main thread is resumed.
sje397