1. Trang chủ
  2. » Công Nghệ Thông Tin

Java Programming for absolute beginner- P21 ppt

20 181 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 20
Dung lượng 359,66 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

The RunnableTestapplication is an example of how to implement the Runnable interface to create a thread.. To get this thread started, you need to create a new Threadobject called t in th

Trang 1

Implementing the Runnable Interface

There is another way to create a thread Instead of extending the Thread class, you can implement the Runnableinterface The Runnableinterface requires that you override one method You guessed it: the run()method To run a Runnable object in a thread, you pass it to the Thread(Runnable)constructor When you invoke start()on the thread, it results in a call to the Runnable’s run()method

The Thread class, itself, implements the Runnable interface That’s why when you extend Thread , you implement the run() method.

The RunnableTestapplication is an example of how to implement the Runnable interface to create a thread Its run()method is exactly the same as the Thread-Testclass’s run()method It just counts to 10 To get this thread started, you need to create a new Threadobject (called t) in the main()method This Runnable object is passed into its constructor and then its start()method is invoked Here

is a listing of the source code:

/*

* RunnableTest

* Demonstrates how to implement the Runnable interface

*/

public class RunnableTest implements Runnable { //must implement the run method

public void run() { for (int i=1; i <= 10; i++) { System.out.println(i);

} } public static void main(String args[]) { RunnableTest test = new RunnableTest();

//Construct a thread with this Runnable Thread t = new Thread(test);

//start the thread t.start();

} }

You can see the output of the RunnableTestapplication in Figure 10.3

What’s the difference between extending Thread and implementing Runnable ? Why would you choose one over the other? Generally, it is better to implement the Runnable interface One good reason for this is that if you are defining a sub-class of another sub-class, such as GUIFrame , you can’t also subclass the Thread

class Inheritance can come from only one direct superclass To get around this

T R I C K

H I N T 358

J a

s o

l ut

n e

Trang 2

FIGURE 10.3

The output of the RunnableTest application is exactly the same as the ThreadTest application.

Problems Associated with Multithreading

When two threads are running concurrently, there is no guarantee which thread will be running at any given time The MultiThreadTest application demon-strates this It has two threads: the original program’s execution thread and a sec-ond thread, an instance of MultiThreadTest, that the original thread starts One

of the threads lists letters in order and the other lists numbers The output of this program is not exactly predictable and multiple runs can produce different output Here is the source code:

/*

* MultiThreadTest

* Demonstrates the unpredictability of multithreading

*/

public class MultiThreadTest extends Thread { public void run() {

for (char a='A'; a <= 'J'; a++) { System.out.println(a);

} } public static void main(String args[]) { MultiThreadTest t = new MultiThreadTest();

//fire off the thread t.start();

//continue on simultaneously for (int i=1; i <= 10; i++) { System.out.println(i);

} } } You can see the output of the MultiThreadTestapplication in Figure 10.4

Trang 3

This is just a simple example, but I’m sure you can imagine what kinds of disas-ters can result if you expect code to be executed in a particular order and you have multiple threads doing different things simultaneously Your data can become corrupted!

Writing Thread-Safe Code

Java provides ways to write thread-safe code, that is, code that can have multiple

threads executing it simultaneously, and not become unstable because of cor-ruption of some kind You can use the synchronizedkeyword as a modifier for methods This keyword makes sure that only one thread can be executing the method at a time It works by locking this, the object that owns the code Only one thread at a time can own a lock for an object Entering a synchronized method ensures that while a thread is inside it, it has an exclusive lock on this Any other thread that needs to get into this method has to wait until the lock is released When a thread passes out of synchronized code, the lock is automati-cally released

public synchronized void mySafeMethod() { … }

360

J a

s o

l ut

n e

FIGURE 10.4

The MultiThreadTest application ran twice with totally different output.

Trang 4

To enter mySafeMethod(), the thread must gain a lock to the instance of the class that defines the method When it gets into mySafeMethod(), it automatically gains the lock to thisand when it passes out of the method, the lock is released, allowing other threads to enter mySafeMethod() You can use the synchronized keyword also to lock blocks of code You can lock on any object:

synchronized (myObject) {

… } myObjectmust not be locked by another thread to enter the block of code defined

in the curly braces Any thread that gets into the curly braces gains a lock to myObject This second method of synchronization is much less commonly used because it can be dangerous to lock any object other than the one that owns the code

volatile is another keyword that has use in multithreaded environments Only variables can be volatile This keyword is not used very often It indicates to the compiler that the variable might be modified out of synch and that multiple threads should be careful when working with it.

Using wait(), notify(), and notifyAll()

The wait(), notify(), and notifyAll()methods allow for threads to be paused and then restarted These methods are defined in the Objectclass They must be called from within synchronized code When a thread enters the wait()method,

it releases the object lock and pauses execution until another thread invokes the notify()or notifyAll()method notify()wakes up one thread waiting on this object and notifyAll()notifies all the threads waiting on this object The wait() method can throw an InterruptedException A thread can be interrupted while

it is waiting or asleep if you invoke the interrupt()method of the Threadclass

public synchronized void getValue() {

if (valueNotSetYet) { try { wait();

} catch (InterruptedException e) { } }

x = value;

} public synchronized void setValue() { value = y;

valueNotSetYet = false;

notify();

}

H I N T

361

Trang 5

In the previous snippet of code, one thread is responsible for getting a value that

is set by a different thread Because you can’t predict exactly when the value will

be set, you need to determine whether the value has been set before you try to get it (assume valueNotSetYetis a booleanvariable that indicates whether the value has been set) If the value hasn’t been set, you wait for it Calling wait() releases the lock and allows the second thread to synchronize on thisand set the value valueNotSetYetto false, and then call notify()to allow the first thread

to retrieve the value it so desperately needs to get

Putting a Thread to Sleep

You can pause a thread for a set number of milliseconds by calling the static Thread.sleep(long)method You will see the importance this feature has for ani-mation when you get to that point to pause between each frame of aniani-mation The longparameter specifies the number of milliseconds the thread sleeps (1000 milliseconds is one second) A sleeping thread can be interrupted, so calling Thread.sleep(long)requires that you handle InterruptedExceptions Here is an example of an application that calls Thread.sleep(long) It alternatively prints

“Tic”and “Toc”to standard output, pausing one second in between each print Here is the source code for SleepTest.java:

/*

* SleepTest

* Demonstrates how to make a Thread sleep

*/

public class SleepTest extends Thread { public void run() {

for (int i=0; i < 10; i++) {

if (i % 2 == 0) System.out.println("Tic");

else System.out.println("Toc");

try { Thread.sleep(1000);

} catch (InterruptedException e) {}

} } public static void main(String args[]) { SleepTest t = new SleepTest();

t.start();

} }

Figure 10.5 shows the output

362

J a

s o

l ut

n e

Trang 6

Performing Animation

Animation is basically done by showing a series of pictures that differ slightly from each other in a way that makes the image appear to be moving If the pic-tures change fast enough, the animation looks smooth In this section, I’ll take you through the process of using threads to animate sprites

The Sprite Class

A sprite, in its simplest definition, is any graphical image that moves, especially

when in relation to computer games A sprite is typically made up of a series of images that are used to animate a motion It also has an (x, y) position and a direction and speed of its movement The Spriteclass I defined for this chapter

is a simple class that encapsulates these concepts It has an array of images, images[], a Point location, location, and another Point, called deltaPoint, which indicates the direction and speed of the sprite

The way this works is the locationpoint is ignored by deltaPoint deltaPoint indicates the distance the sprite will move in both the xdirection and the y direc-tion from where it currently is, wherever that might be, every time the sprite is updated There is another member, currentImgIndex,which keeps track of the images[] Imageelement (the actual image) that is set as the current image to be displayed The Spriteclass has its getand setmethods for modifying the pro-tected members The constructor accepts the array of images, the starting loca-tion, and also the deltaPoint Pointobject

The update()method sets the current image to the next image (if it gets past the last image, it loops back to the first one), and then it moves the current location based on the value of deltaPointby calling the translate(int, int) method

This method belongs to the Point class and moves the Point object’s location based on the change in xand the change in ythat you pass in as its parameters

363

FIGURE 10.5

To really benefit from this, you kinda sorta have to run it yourself.

Trang 7

The Sprite class doesn’t perform any animation on its own It relies on other classes to call its update()method, which creates the illusion of motion Here is the source listing for Sprite.java:

/*

* Sprite

* Encapsulates images for animation.

*/

import java.awt.*;

public class Sprite { protected Image[] images;

protected Point location;

//indicates the change in (x, y) protected Point deltaPoint;

protected int currentImgIndex;

public Sprite(Image[] imgs, Point loc, Point delta) { images = imgs;

currentImgIndex = 0;

location = new Point(loc.x, loc.y);

deltaPoint = new Point(delta.x, delta.y);

} public Image getCurrentImage() { return images[currentImgIndex];

} public void setLocation(Point loc) { location = new Point(loc.x, loc.y);

} public Point getLocation() { return new Point(location.x, location.y);

} public void setDeltaPoint(Point dest) { deltaPoint = new Point(dest.x, dest.y);

} public Point getDeltaPoint() { return new Point(deltaPoint.x, deltaPoint.y);

} public void update() { currentImgIndex = (currentImgIndex + 1) % images.length;

location.translate(deltaPoint.x, deltaPoint.y);

} }

364

J a

s o

l ut

n e

Trang 8

Testing the Sprite Class

The SpriteTestclass tests the Sprite class by giving it some images, specifying its location, and delta point, and repeatedly calling its update() method from within a thread Figure 10.6 shows the three images that make up the animation

365

FIGURE 10.6

It’s BoitMan! These images are animated by the SpriteTest class.

Here is the source code for SpriteTest.java: /*

* SpriteTest

* Tests the Sprite class

*/

import java.awt.*;

public class SpriteTest extends GUIFrame implements Runnable { Sprite sprite;

public SpriteTest(Image[] images, Point loc, Point dest) { super("Sprite Animation Test");

MediaTracker mt = new MediaTracker(this);

for (int i=0; i < images.length; i++) { mt.addImage(images[i], i);

} try { mt.waitForAll();

} catch (InterruptedException e) {}

sprite = new Sprite(images, loc, dest);

} public static void main(String args[]) { Image[] imgs = { Toolkit.getDefaultToolkit().getImage("b1.gif"),

Toolkit.getDefaultToolkit().getImage("b2.gif"), Toolkit.getDefaultToolkit().getImage("b3.gif") };

SpriteTest spriteTest = new SpriteTest(imgs, new Point(0, 0),

new Point(3, 3));

spriteTest.setSize(300, 300);

spriteTest.setVisible(true);

Thread runner = new Thread(spriteTest);

runner.start();

}

Trang 9

//assumes animation moves to the right, down, or both public void run() {

while (sprite.getLocation().x < getSize().width

&& sprite.getLocation().y < getSize().height) { repaint();

sprite.update();

try { Thread.sleep(50);

} catch (InterruptedException e) {}

} } public void paint(Graphics g) { g.drawImage(sprite.getCurrentImage(), sprite.getLocation().x,

sprite.getLocation().y, this);

} }

It is a GUIFramethat constructs a Spriteobject by passing in an array of images consisting of b1.gif, b2.gif, and b3.gif The second argument to the constructor is new Point(0, 0)so the sprite starts in the top-left corner of the GUIFrame The third argument is new Point(3, 3), so every time the sprite is updated by call-ing its update() method, it will move three generic units (often pixels) to the right and three down

SpriteTestimplements the Runnableinterface and overrides run()to move the sprite until it is no longer in the visible GUIFramearea It calls repaint()to dis-play the image, and then calls sprite.update()to update the sprite to its next frame, sleeps for 50 milliseconds, and then repeats this dance The paint(Graph-ics)method paints sprite’s image at its current location, which it gets by call-ing sprite.getLocation().x and sprite.getLocation().y Figure 10.7 hints at what this looks like; however, you have to run it for yourself to actually see the animation

366

J a

s o

l ut

n e

FIGURE 10.7

Go BoitMan, Go!

Trang 10

Double Buffering

Did you notice that ugly flickering while BoitMan was running across the screen? This is because the drawing is taking place directly onto the screen To eliminate the flickering, you need to paint the image to an off-screen buffer first, and then copy the entire off-screen image to the screen This technique is called

double buffering Here’s how it works.

Calling a component’s repaint()method results in a call to the update(Graph-ics)method, which clears the component’s graphics with the background color

You actually see this happening on-screen, which is the main cause of the flick-ering Then the update(Graphics)method sets the color to the foreground color and invokes paint(Graphics) You see the background color for a split second, and then you see the image again This is where the flickering comes from

To prevent the flickering, override update(Graphics)so that it doesn’t clear the background It just calls paint(Graphics)directly Then from paint(), create an image buffer, which is an invisible image You create the off-screen image buffer

by invoking the createImage(int, int)method that is defined in the Component class The arguments are its width and its height Then draw on to the buffered image and then copy the whole thing to the screen The SpriteNoFlickerTest application performs double-buffering:

/*

* SpriteTest

* Tests the Sprite class

*/

import java.awt.*;

public class SpriteNoFlickerTest extends GUIFrame implements Runnable { Sprite sprite;

Image offImg;

public SpriteNoFlickerTest(Image[] images, Point loc, Point dest) { super("Sprite Animation Test (No Flicker)");

MediaTracker mt = new MediaTracker(this);

for (int i=0; i < images.length; i++) { mt.addImage(images[i], i);

} try { mt.waitForAll();

} catch (InterruptedException e) {}

sprite = new Sprite(images, loc, dest);

} public static void main(String args[]) { Image[] imgs = { Toolkit.getDefaultToolkit().getImage("b1.gif"),

Toolkit.getDefaultToolkit().getImage("b2.gif"), Toolkit.getDefaultToolkit().getImage("b3.gif") };

367

Ngày đăng: 03/07/2014, 05:20

TỪ KHÓA LIÊN QUAN