Principle 15.5.1. EFFECTIVE DESIGN: Busy Waiting.
Instead of busy waiting, a thread that sleeps for a brief period on each iteration is a better way to introduce a delay into an algorithm.
www.cs.trincoll.edu
. Our program will have to load the following four URLs:http://www.cs.trincoll.edu/~ram/jjj/labs/ch09/slideshow/demo/demo0.gif
http://www.cs.trincoll.edu/~ram/jjj/labs/ch09/slideshow/demo/demo1.gif
http://www.cs.trincoll.edu/~ram/jjj/labs/ch09/slideshow/demo/demo2.gif
http://www.cs.trincoll.edu/~ram/jjj/labs/ch09/slideshow/demo/demo3.gif
paint()
method to display an image each time it is repainted:public void paint(Graphics g) {
if (currentImage != null)
g.drawImage(currentImage, 10, 10, this);
}
currentImage
instance variable will be set initially to null
. Each time an image is downloaded, it will be set to refer to that image. Because paint()
is called before the program starts downloading the images, it is necessary to guard against attempting to draw a null
image, which would lead to an exception.for (int k = 0; k < 1000000; k++ )
;// Busy waiting
sleep()
for 5 seconds between each slide. JFrame
subclass will take care of downloading and displaying the images and starting the timer thread.Runnable
interface so that it can run as a separate thread. It will repeatedly sleep for 5 seconds and then tell the frame to display the next side.SlideShowFrame
class
nextImg
variable as an array index to keep track of the next image. Even though it isn’t absolutely necessary, we could use a third variable here, currentImage
, to keep track of the current image being displayed. Thus, our frame needs the following instance variables:private static final int NIMGS = 4;
private Image[] slide = new Image[NIMGS];
private Image currentImage = null;
private int nextImg = 0;
private String baseURL = "http://www.cs.trincoll.edu/~ram/jjj/labs/ch09/slideshow/demo/";
paint()
method is responsible for displaying currentImage
, so all this method needs to do is to update both currentImage
and nextImg
. This method should be designed so that it can be called by the Timer
thread whenever it is time to display the next slide, so it should be a public
method. It can be a void
method with no parameters, because the frame already contains all the necessary information to display the next slide. Thus, there’s no need for information to be passed back and forth between Timer
and this method:public void nextSlide() {
currentImage = slide[nextImg];
nextImg = (nextImg + 1) % NIMGS;
repaint();
}// nextSlide()
currentImage
to whatever slide
is designated by nextImg
and it then updates nextImg
’s value. Note here the use of modular arithmetic to compute the value of nextImg
. Given that NIMGS
is 3, this algorithm will cause nextImg
to take on the repeating sequence of values 0, 1, 2, 0, 1, 2, and so forth. Finally, the method calls repaint()
to display the image.x % N
) is useful for cycling repeatedly through the values \(0, 1, \ldots, N-1\text{.}\)
SlideShowFrame()
method will have two tasks:slide[]
.Timer
thread.javax.imageio.ImageIO.read()
method. Here we just place these method calls in a loop:for (int k=0; k < NIMGS; k++) {
try {
slide[k] = ImageIO.read( new URL(baseURL + "demo" + k + ".gif"));
}
catch (MalformedURLException e) {
System.out.println( "Malformed URL: " + e) ;
}
catch (IOException e) {
System.out.println("I/O Exception " + e);
}
}
String
and concatenate it right into the URL specification. This allows us to have URLs containing “demo0.gif,” ... “demo3.gif”. This makes our program easily extensible should we later decide to add more slides to the show. Note also the use of the class constant NIMGS
as the loop bound. This too adds to the program’s extensibility.k
) with a string lets you create file names of the form file1.gif
, file2.gif
, and so on.Timer
thread involves creating an instance of the Timer
class and calling its start()
method:Thread timer = new Thread(new Timer(this));
timer.start();
Timer
is passed a reference to this
frame. This enables Timer
to call the frame’s nextSlide()
method every 5 seconds. This programming technique is known as callback and the nextSlide()
method is an example of a callback method (Figure 15.5.7).
SlideShowFrame
, which is shown in Listing 15.5.9.Timer
Class
Timer
class is a subclass of Thread
, which means it must implement the run()
method. Recall that we never directly call a thread’s run()
method. Instead, we call its start()
method, which automatically calls run()
. This particular thread has a very simple and singular function. It should call the SlideShowFrame.nextSlide()
method and then sleep for 5 seconds. So its main algorithm will be:while (true) {
frame.nextSlide();
sleep( 5000 );
}
Thread.sleep()
throws the InterruptedException
. This means that we’ll have to embed this while loop in a try/catch
block.nextSlide()
method, we also need a reference to the SlideShowFrame
, so we need to give it a reference, such as an instance variable, as well as a constructor that allows the frame to pass Timer
a reference to itself.Timer
is shown in Listing 15.5.10. To see how it works, download it from the Java, Java, Java Web site and run it.SlideShowFrame()
constructor: // Use File for local file in replit project instead of URL
File imageFile = new File("image" + k + ".jpg");
slide[k] = ImageIO.read(imageFile);
SlideShowFrame
if you wanted to play a soundtrack along with your slides. Assume that the sounds are stored in a sequence of files, “sound0.au,” sound1.au,’’ and so forth, on your Web site.