Java Thread Programming Java Thread Programming Paul Hyde Copyright © 1999 Sams Publishing Java Thread Programming Paul Hyde Copyright © 1999 by Sams Publishing Executive Editor Tim Ryan Acquisitions Editor Steve Anglin Development Editors Tiffany Taylor Jon Steever Managing Editor Jodi Jensen Senior Editor Susan Ross Moore Copy Editors Margaret Berson Kate Talbot Indexer Rebecca Hornyak Proofreaders Mona Brown Jill Mazurczyk Technical Editors Alexandre Calsavara Mike Forsythe Team Coordinator Karen Opal Software Development Specialist Michael Hunter Interior Design Anne Jones Cover Design Anne Jones Copy Writer Eric Borgert Layout Technicians Stacey DeRome Ayanna Lacey Heather Miller All rights reserved No part of this book shall be reproduced, stored in a retrieval system, or transmitted by any means, electronic, mechanical, photocopying, recording, or otherwise, without written permission from the publisher No patent liability is assumed with respect to the use of the information contained herein Although every precaution has been taken in the preparation of this book, the publisher and author assume no responsibility for errors or omissions Neither is any liability assumed for damages resulting from the use of the information contained herein International Standard Book Number: 0-672-31585-8 01 00 99 Trademarks All terms mentioned in this book that are known to be trademarks or service marks have been appropriately capitalized Sams Publishing cannot attest to the accuracy of this information Use of a term in this book should not be regarded as affecting the validity of any trademark or service mark Sun, Sun Microsystems, SunWorld, Java, and HotJava are trademarks or registered trademarks of Sun Microsystems, Inc Toc Introduction Java Thread Programming Paul Hyde Copyright © 1999 Sams Publishing Introduction Structure of This Book This book is for those of you who have started working with Java and have realized that you want to develop multithreaded applications and applets I don’t assume that you know anything about thread programming, so the book starts off with simple, straightforward examples From there, the chapters become more advanced and comprehensively cover all aspects of thread programming in Java The second part of the book is dedicated to demonstrating various advanced techniques that can be used in the real world Chapters 1 through 10 can be read in order because each chapter builds upon the concepts in the preceding one You can hop around the techniques in Chapters 11 through 18, reading them in just about any order Some of the techniques are so valuable that they are used in demonstrating other techniques, so you can read up on each technique as you come across it I developed the example code used in this book using the Java 2 SDK, Standard Edition, version 1.2 (also known as JDK 1.2) from Sun Microsystems I used this development kit on an Intel Pentium 166MHz machine running Microsoft Windows 95 In this book, some of the statements in the code listings appear in bold-face type simply for emphasis These source code files are available for download from www.samspublishing.com When you reach that page, click the Product Support link On the next page, enter this book’s ISBN number (0672315858) to access the page containing the code The following is an overview of what is covered in each of the chapters (not available) Toc Java Thread Programming ISBN: 0672315858 by Paul Hyde Sams © 1999, 510 pages Learn how to use threads for faster, more efficient Java programming Table of Contents Back Cover Source Code Synopsis by Rebecca Rohan Professional Java developers who've come as far as they can without exploiting threads will find their skills bumped up a few notches by the time they finish Paul Hyde's Java Thread Programming In a five-and-a-halfpage first chapter, the book gives a basic concept briefing, then gets down to business with an examplerich education from the starting thread through interthread communication, thread groups, thread pooling, threads and Swing, and more You'll get an experienced voice on how to gracefully exit from a thread and find out when to use the lead-between-the-eyes SureStop class instead You'll even find out when multiple threads aren't a good idea If you're serious about learning what it takes to do Java really, really well, this book is a good place to invest your time Table of Contents Java Thread Programming Introduction Part I Threads Chapter 1 Chapter 2 Chapter 3 - Introduction to Threads - A Simple Two-Thread Example - Creating and Starting a Thread Chapter 4 Chapter 5 Chapter 6 Chapter 7 Chapter 8 Chapter 9 Chapter 10 - Implementing Runnable Versus Extending Thread - Gracefully Stopping Threads - Thread Prioritization - Concurrent Access to Objects and Variables - Inter-thread Communication - Threads and Swing - Thread Groups Part II Techniques Chapter 11 Chapter 12 Chapter 13 Chapter 14 Chapter 15 Chapter 16 Chapter 17 Chapter 18 - Self-Running Objects - Exception Callback - Thread Pooling - Waiting for the Full Timeout - Breaking Out of a Blocked I/O State - The SureStop Utility - The BooleanLock Utility - First-In-First-Out (FIFO) Queue Part III Appendixes Appendix A - The Thread API Appendix B - The ThreadGroup API Back Cover Learn professional thread management techniques from Paul Hyde, a professional Java developer, Sun Certified Programmer for the Java 2 Platform, and advanced Java language instructor Apply the concepts, code, and realworld solutions in this book to make your Java applications faster, more stable, and more robust Written by a professional software developer for software developers, Java Thread Programming provides a code-intensive, solution-oriented approach to mastering threads LEARN THE CONCEPTS AND BUILD THE APPLICATIONS Start by learning the basics of multithreaded programming in Java and work up to the more advanced concepts Suitable tutorial for Java developers that have never worked with threads before, and an excellent reference and source of proven, advanced techniques for Java developers who have had experience working with threads Explains how volatile and synchronized should be used to control concurrent access to objects and variables and how to avoid deadlocks Discusses how to implement safe and efficient inter-thread communications using the wait/notify mechanism Explains how thread prioritization and scheduling affect the execution of threads within an application Discusses pros and cons to different approaches and teaches you how to choose the best solutions Covers the proper use of threads and Swing, and shows how to use threads to create animation Shows you how to use the Collections API in a thread-safe manner Comprehensively covers multithread code based on the Java 2 SDK version 1.2.1 and discusses the differences form JDK 1.1 and JDK 1.0 About the Authors Paul Hyde is a professional Java developer and Sun Certified Programmer for the Java 2 Platform He began developing Java applications at AT&T in 1996 and now has over three years of on-the-job Java development experience Paul is currently a senior Java consultant for Programix Incorporated, the consulting company he founded in early 1997 He also develops and teaches introductory to advanced Java courses for IT professionals and developers Chapter 1 - Introduction to Threads Java Thread Programming Paul Hyde Copyright © 1999 Sams Publishing Chapter 1: Introduction to Threads Overview Isn’t it nice to be able to read and scroll the text of a Web page while the graphics continue to load? How about having a document in a word processor print in the background while you open another document for editing? Perhaps you’ve enjoyed writing a response to an email message while another incoming message with a large file attached is quietly downloaded simultaneously? Threads make all this convenient functionality possible by allowing a multithreaded program to do more than one task at a time This book helps you learn the skills and techniques necessary to incorporate that kind of useful functionality into your Java programs Toc Chapter 1 - Introduction to Threads Java Thread Programming Paul Hyde Copyright © 1999 Sams Publishing What Is a Thread? When a modern operating system wants to start running a program, it creates a new process A process is a program that is currently executing Every process has at least one thread running within it Sometimes threads are referred to as lightweight processes A thread is a path of code execution through a program, and each thread has its own local variables, program counter (pointer to the current instruction being executed), and lifetime Most modern operating systems allow more than one thread to be running concurrently within a process When the Java Virtual Machine (JavaVM, or just VM) is started by the operating system, a new process is created Within that process, many threads can be spawned (created) Normally, you would think of Java code execution starting with the main() method and proceeding in a path through the program until all the statements in main() are completed This is an example of a single thread This “main” thread is spawned by the JavaVM, which begins execution with the main() method, executes all the statements in main(), and dies when the main() method completes A second thread is always running in the JavaVM: the garbage collection thread It cleans up discarded objects and reclaims their memory Therefore, even a simple Java program that only prints Hello World to System.out is running in a multithreaded environment: The two threads are the main thread and the garbage collection thread When a Java program includes a graphical user interface (GUI), the JavaVM automatically starts even more threads One of these threads is in charge of delivering GUI events to methods in the program; another is responsible for painting the GUI window For example, imagine that a GUI-based program’s main thread is performing a complex and long-running calculation and that while this is going on, the user clicks a Stop Calculation button The GUI event thread would then invoke the event handling code written for this button, allowing the calculation thread to be terminated If only one thread was present, both of these could not be done simultaneously, and interruption would be difficult public final boolean isDaemon() Returns true if this thread is a daemon thread, or false otherwise A daemon thread continues to run only as long as there is at least one nondaemon thread still running in the VM Related method: setDaemon() See Chapter 5 for more information isInterrupted() public boolean isInterrupted() Returns the interrupted status of this thread and (unlike interrupted())does not change the status Related methods: interrupt(), Thread.interrupted() See Chapter 5 for more information join() public final void join() throws InterruptedException Causes the current thread to block and wait an unlimited amount of time for this thread to die It will throw an InterruptedException if interrupted while waiting for this thread to die Related methods: join(long), join(long, int), interrupt(), and isAlive() See Chapter 8, “Inter-thread Communication,” for more information join(long) public final synchronized void join(long ms) throws InterruptedException Causes the current thread to block and wait ms milliseconds for this thread to die It will throw an InterruptedException if interrupted while waiting for this thread to die Related methods: join(), join(long, int), interrupt(), and isAlive() See Chapter 8 for more information join(long, int) public final synchronized void join(long ms, int ns) throws InterruptedException Causes the current thread to block and wait ms milliseconds plus ns nanoseconds for this thread to die It will throw an InterruptedException if interrupted while waiting for this thread to die Related methods: join(), join(long), interrupt(), and isAlive() See Chapter 8 for more information run() public void run() If this method was not overridden in a subclass, it does nothing but call the run() method of the Runnable passed to the constructor If no Runnable was specified, this method returns right away When this method returns, the thread dies Related method: start() See Chapter 4, “Implementing Runnable Versus Extending Thread,” for more information setContextClassLoader(ClassLoader) public void setContextClassLoader(ClassLoader newLoader) throws SecurityException Specifies a new class loader for this thread Throws a SecurityException if the current thread is not permitted to modify this thread Related method: getContextClassLoader() setDaemon(boolean) public final void setDaemon(boolean newStatus) throws SecurityException If newStatus is true, this thread will be a daemon thread and will automatically die when no non-daemon threads are left running in the VM If newStatus is false, this thread is a normal thread This method must be called before this thread is started It throws a SecurityException if the current thread is not permitted to modify this thread Related method: isDaemon() See Chapter 5 for more information setName(String) public final void setName(String newName) throws SecurityException Changes the name of this thread to newName Throws a SecurityException if the current thread is not permitted to modify this thread Related method: getName() See Chapter 3 for more information setPriority(int) public final void setPriority(int newPriority) throws SecurityException, IllegalArgumentException Changes the thread-scheduling priority of this thread to newPriority If this thread’s ThreadGroup has a maximum priority set for the group and newPriority exceeds that maximum, newPriority is silently reduced to the group’s maximum allowable value Throws an IllegalArgumentException if newPriority is not at least Thread.MIN_PRIORITY or if greater than Thread.MAX_PRIORITY Throws a SecurityException if the current thread is not permitted to modify this thread Related method: getPriority() Related methods on ThreadGroup are setMaxPriority() and getMaxPriority() See Chapter 6 for more information start() public native synchronized void start() throws IllegalThreadStateException Causes the VM to spawn a new thread that begins execution by calling run(); start() immediately returns Throws IllegalThreadStateException (subclass of RuntimeException) if the thread has already been started Related methods: run(), isAlive(), and stop() See Chapter 3 for more information toString() public String toString() Returns a string representation of the current state of this thread including its name, priority, and thread group Toc Appendix A - The Thread API Java Thread Programming Paul Hyde Copyright © 1999 Sams Publishing Deprecated Methods The methods in this section have been deprecated and should only be used if absolutely necessary Alternatives for stop(), suspend(), and resume() are presented in Chapter 5 countStackFrames() public native int countStackFrames() Deprecated! Counts the number of stack frames for a suspended thread resume() public final void resume() throws SecurityException Deprecated! Allows this thread to resume execution after being suspended Throws a SecurityException if the current thread is not permitted to access this thread Related method: suspend() See Chapter 5 for more information stop() public final void stop() throws SecurityException Deprecated! Causes this thread to stop what it is doing and throw a ThreadDeath (subclass of Error) Throws a SecurityException if the current thread is not permitted to modify this thread Related methods: start(), suspend(), resume() See Chapter 5 for more information stop(Throwable) public final synchronized void stop(Throwable except) throws SecurityException Deprecated! Causes this thread to stop what it is doing and throw the Throwable object except Throws a SecurityException if the current thread is not permitted to modify this thread Related methods: stop(), start(), suspend(), resume() See Chapter 5 for more information suspend() public final void suspend() throws SecurityException Deprecated! Causes this thread to temporarily stop execution until the resume() method is invoked Throws a SecurityException if the current thread is not permitted to modify this thread Related methods: resume(), stop() See Chapter 5 for more information Toc Appendix B - The ThreadGroup API Java Thread Programming Paul Hyde Copyright © 1999 Sams Publishing Appendix B: The ThreadGroup API Overview This appendix summarizes the public and protected members of the ThreadGroup class It is based on Sun Microsystems’ Java Development Kit 1.2 Information has been combined from Sun’s API documentation, source code, reflection on the distributed classes, and the Java Language Specification Many of the methods and both of the constructors can throw a SecurityException SecurityException is a subclass of RuntimeException, so try/catch blocks are not required for any of the methods of ThreadGroup that might throw it By default, an application does not have a SecurityManager defined (using JDK 1.0, 1.1, or 1.2 from Sun Microsystems) An applet, on the other hand, might have a SecurityManager present In general, this exception is thrown when the calling thread is not permitted to perform the requested action Many times, the security check is done by invoking the checkAccess() method on ThreadGroup, which in turn checks to see if a SecurityManager has been installed, and if so, invokes its checkAccess(ThreadGroup) method For most of your application programming, you can safely ignore the possibility of a SecurityException being thrown Throughout this appendix, the terms “this thread” and “current thread” are used The “current thread” term refers to the thread that invoked the method The “this thread” term refers to the Thread instance that the method will affect For example, suppose threadA executes the following statement: threadB.checkAccess(); threadA would be considered the “current thread,” and threadB would be considered “this thread.” The API documentation for checkAccess() would read something like, “throws a SecurityException if the current thread is not permitted to access this thread.” This translates to “throws a SecurityException if threadA is not permitted to access threadB.” It’s a subtle difference worth noticing Toc Appendix B - The ThreadGroup API Java Thread Programming Paul Hyde Copyright © 1999 Sams Publishing Constructors Two constructors exist for creating new thread groups ThreadGroup(ThreadGroup, String) public ThreadGroup(ThreadGroup parentGroup, String groupName) throws SecurityException Creates a new ThreadGroup that is a child group of parentGroup and has the name groupName The parent group’s checkAccess() method is invoked to see if the current thread is allowed to create a new ThreadGroup in parentGroup, which can result in a SecurityException being thrown If parentGroup is null, a NullPointerException will be thrown The new ThreadGroup will have the same maximum thread priority and daemon status as its parent These can be changed with setMaxPriority() and setDaemon() See Chapter 10 for more information ThreadGroup(String) public ThreadGroup(String groupName) throws SecurityException Equivalent to using the main constructor like this: ThreadGroup(Thread.currentThread().getThreadGroup(), groupName) Toc Appendix B - The ThreadGroup API Java Thread Programming Paul Hyde Copyright © 1999 Sams Publishing Instance Methods There are no static methods on ThreadGroup; all the methods are instance methods activeCount() public int activeCount() Returns the number of active threads in this thread group and all its subgroups Related method: enumerate() See Chapter 10 for more information activeGroupCount() public int activeGroupCount() Returns the number of active thread groups in this thread group and all its subgroups checkAccess() public final void checkAccess() throws SecurityException Checks to see if there is a SecurityManager and if it will allow the current thread to access this ThreadGroup Throws a SecurityException if the current thread is denied access Many other methods of ThreadGroup invoke checkAccess() internally destroy() public final void destroy() throws SecurityException, IllegalThreadStateException Destroys this thread group and all its subgroups If any of the groups is not empty (meaning that all the threads within have not died), an IllegalThreadStateException will be thrown It throws a SecurityException if the current thread is denied access to this thread group enumerate(Thread[ ], boolean) public int enumerate(Thread[] dest, boolean includeSubgroups) throws SecurityException Collects a reference to all the threads in this thread group (and recursively all its subgroups if includeSubgroups is true) and copies these Thread references into dest A SecurityException can be thrown if the operation is not allowed by checkAccess() The number of references copied into dest is returned If dest is too small, the extra Thread references are quietly thrown away The activeCount() method can be used to estimate the size needed for the dest array In general, dest should be about twice the size you think you’ll need to be sure that all the threads get copied into it Related methods: activeCount(), enumerate(Thread[ ]) See Chapter 10 for more information enumerate(Thread[ ]) public int enumerate(Thread[] dest) throws SecurityException Equivalent to: enumerate(dest, true) enumerate(ThreadGroup[ ], boolean) public int enumerate(ThreadGroup[] dest, boolean includeSubgroups) throws SecurityException Collects a reference to all the thread groups in this thread group (and recursively all its subgroups if includeSubgroups is true) and copies these ThreadGroup references into dest A SecurityException can be thrown if the operation is not allowed by checkAccess() The number of references copied into dest is returned If dest is too small, the extra ThreadGroup references are quietly thrown away The activeGroupCount() method can be used to estimate the size needed for the dest array In general, dest should be about twice the size you think you’ll need to be sure that all the thread groups get copied into it Related methods: activeGroupCount(), enumerate(ThreadGroup[]) enumerate(ThreadGroup[ ]) public int enumerate(ThreadGroup[] dest) throws SecurityException Equivalent to: enumerate(dest, true) getMaxPriority() public final int getMaxPriority() Returns the maximum priority that any thread in this group or one of its subgroups can have Related method: setMaxPriority() See Chapters 6 and 10 for more information getName() public final String getName() Returns the name of this thread group See Chapter 10 for more information getParent() public final ThreadGroup getParent() throws SecurityException Returns the parent thread group of this thread group, or null if this thread group does not have a parent (top thread group) A SecurityException can be thrown if the parent is not null and its checkAccess() method disapproves See Chapter 10 for more information interrupt() public final void interrupt() throws SecurityException Interrupts all the threads in this thread group and all its subgroups A SecurityException can be thrown if any of the threads or thread groups disapprove See Chapter 5 for more information isDaemon() public final boolean isDaemon() Returns true if this thread group is a daemon thread group, false otherwise A daemon thread group is automatically destroyed when the last of its threads dies Related method: setDaemon() isDestroyed() public synchronized boolean isDestroyed() Returns true if this thread group has been destroyed, false otherwise Related method: destroy() list() public void list() Dumps information about all the threads in this thread group and all its subgroups to System.out by invoking toString() on each Thread Really only useful for debugging parentOf(ThreadGroup) public final boolean parentOf(ThreadGroup group) Returns true if this thread group is an ancestor of group, false otherwise Related method: getParent() setDaemon(boolean) public final void setDaemon(boolean newStatus) throws SecurityException If newStatus is true, this thread group will be automatically destroyed when all its threads have died Otherwise, if newStatus is false, it will be a normal thread group A SecurityException will be thrown if the current thread does not have permission to modify this thread group Related method: isDaemon() setMaxPriority(int) public final void setMaxPriority(int newMax) throws SecurityException Sets the maximum priority that a thread in this thread group (and all its subgroups) can have Threads already running at a priority higher than this are not affected A SecurityException will be thrown if the current thread does not have permission to modify this thread group Related method: getMaxPriority() toString() public String toString() Returns a string representation of this thread group including its name and maximum thread priority uncaughtException(Thread, Throwable) public void uncaughtException(Thread deadThread, Throwable exception) The Java VM calls this method when a thread in this thread group throws an Exception or Error that is not caught inside run() The thread that did not catch the exception is deadThread, and the Throwable that it did not catch is exception This method can be over-ridden in a subclass of ThreadGroup to intercept this information If it is not overridden, the default behavior is for it to invoke the uncaughtException() method of this group’s parent group If this group does not have a parent and the Throwable is anything other than an instance of ThreadDeath, a stack trace is printed to System.err Toc Appendix B - The ThreadGroup API Java Thread Programming Paul Hyde Copyright © 1999 Sams Publishing Deprecated Methods The methods in this section have been deprecated and should only be used if absolutely necessary allowThreadSuspension(boolean) public boolean allowThreadSuspension(boolean newState) Deprecated! Behavior has never been fully specified resume() public final void resume() throws SecurityException Deprecated! Resumes all the threads in this thread group (and its subgroups) A SecurityException will be thrown if the current thread does not have access permission Related method: suspend() See Chapter 10 for more information stop() public final void stop() throws SecurityException Deprecated! Stops all the threads in this thread group (and its subgroups) A SecurityException will be thrown if the current thread does not have access permission Related methods: suspend() and resume() See Chapter 10 for more information suspend() public final void suspend() throws SecurityException Deprecated! Suspends all the threads in this thread group (and its subgroups) A SecurityException will be thrown if the current thread does not have access permission Related method: resume() See Chapter 10 for more information ... Possible Output from a Run of TwoThread .java Main thread New thread Main thread New thread Main thread New thread Main thread New thread Main thread New thread Main thread New thread Main thread New thread Main thread New thread. .. Chapter 2 - A Simple Two -Thread Example Java Thread Programming Paul Hyde Copyright © 1999 Sams Publishing Extending the java. lang .Thread Class An instance of the java. lang .Thread class is associated with each thread. .. The following is an overview of what is covered in each of the chapters (not available) Toc Java Thread Programming ISBN: 0672315858 by Paul Hyde Sams © 1999, 510 pages Learn how to use threads for faster, more efficient Java programming Table of Contents