- •Contents
- •Preface
- •Introduction to Computers, the Internet and the Web
- •1.3 Computer Organization
- •Languages
- •1.9 Java Class Libraries
- •1.12 The Internet and the World Wide Web
- •1.14 General Notes about Java and This Book
- •Sections
- •Introduction to Java Applications
- •2.4 Displaying Text in a Dialog Box
- •2.5 Another Java Application: Adding Integers
- •2.8 Decision Making: Equality and Relational Operators
- •Introduction to Java Applets
- •3.2 Sample Applets from the Java 2 Software Development Kit
- •3.3 A Simple Java Applet: Drawing a String
- •3.4 Two More Simple Applets: Drawing Strings and Lines
- •3.6 Viewing Applets in a Web Browser
- •3.7 Java Applet Internet and World Wide Web Resources
- •Repetition)
- •Class Attributes
- •5.8 Labeled break and continue Statements
- •5.9 Logical Operators
- •Methods
- •6.2 Program Modules in Java
- •6.7 Java API Packages
- •6.13 Example Using Recursion: The Fibonacci Series
- •6.16 Methods of Class JApplet
- •Class Operations
- •Arrays
- •7.6 Passing Arrays to Methods
- •7.8 Searching Arrays: Linear Search and Binary Search
- •Collaboration Among Objects
- •8.2 Implementing a Time Abstract Data Type with a Class
- •8.3 Class Scope
- •8.4 Controlling Access to Members
- •8.5 Creating Packages
- •8.7 Using Overloaded Constructors
- •8.9 Software Reusability
- •8.10 Final Instance Variables
- •Classes
- •8.16 Data Abstraction and Encapsulation
- •9.2 Superclasses and Subclasses
- •9.5 Constructors and Finalizers in Subclasses
- •Conversion
- •9.11 Type Fields and switch Statements
- •9.14 Abstract Superclasses and Concrete Classes
- •9.17 New Classes and Dynamic Binding
- •9.18 Case Study: Inheriting Interface and Implementation
- •9.19 Case Study: Creating and Using Interfaces
- •9.21 Notes on Inner Class Definitions
- •Strings and Characters
- •10.2 Fundamentals of Characters and Strings
- •10.21 Card Shuffling and Dealing Simulation
- •Handling
- •Graphics and Java2D
- •11.2 Graphics Contexts and Graphics Objects
- •11.5 Drawing Lines, Rectangles and Ovals
- •11.9 Java2D Shapes
- •12.12 Adapter Classes
- •Cases
- •13.3 Creating a Customized Subclass of JPanel
- •Applications
- •Controller
- •Exception Handling
- •14.6 Throwing an Exception
- •14.7 Catching an Exception
- •Multithreading
- •15.3 Thread States: Life Cycle of a Thread
- •15.4 Thread Priorities and Thread Scheduling
- •15.5 Thread Synchronization
- •15.9 Daemon Threads
- •Multithreading
- •Design Patterns
- •Files and Streams
- •16.2 Data Hierarchy
- •16.3 Files and Streams
- •Networking
- •17.2 Manipulating URIs
- •17.3 Reading a File on a Web Server
- •17.4 Establishing a Simple Server Using Stream Sockets
- •17.5 Establishing a Simple Client Using Stream Sockets
- •17.9 Security and the Network
- •18.2 Loading, Displaying and Scaling Images
- •18.3 Animating a Series of Images
- •18.5 Image Maps
- •18.6 Loading and Playing Audio Clips
- •18.7 Internet and World Wide Web Resources
- •Data Structures
- •19.4 Linked Lists
- •20.8 Bit Manipulation and the Bitwise Operators
- •Collections
- •21.8 Maps
- •21.9 Synchronization Wrappers
- •21.10 Unmodifiable Wrappers
- •22.2 Playing Media
- •22.3 Formatting and Saving Captured Media
- •22.5 Java Sound
- •22.8 Internet and World Wide Web Resources
- •Hexadecimal Numbers
15
Multithreading
Objectives
•To understand the notion of multithreading.
•To appreciate how multithreading can improve performance.
•To understand how to create, manage and destroy threads.
•To understand the life cycle of a thread.
•To study several examples of thread synchronization.
•To understand thread priorities and scheduling.
•To understand daemon threads and thread groups.
The spider’s touch, how exquisitely fine!
Feels at each thread, and lives along the line.
Alexander Pope
A person with one watch knows what time it is; a person with two watches is never sure.
Proverb
Conversation is but carving!
Give no more to every guest,
Than he’s able to digest.
Jonathan Swift
Learn to labor and to wait.
Henry Wadsworth Longfellow
The most general definition of beauty…Multeity in Unity.
Samuel Taylor Coleridge
838 |
Multithreading |
Chapter 15 |
Outline
15.1Introduction
15.2Class Thread: An Overview of the Thread Methods
15.3Thread States: Life Cycle of a Thread
15.4Thread Priorities and Thread Scheduling
15.5Thread Synchronization
15.6Producer/Consumer Relationship without Thread Synchronization
15.7Producer/Consumer Relationship with Thread Synchronization
15.8Producer/Consumer Relationship: The Circular Buffer
15.9Daemon Threads
15.10Runnable Interface
15.11Thread Groups
15.12(Optional Case Study) Thinking About Objects: Multithreading
15.13(Optional) Discovering Design Patterns: Concurrent Design Patterns
Summary • Terminology • Self-Review Exercises • Answers to Self-Review Exercises • Exercises
15.1 Introduction
It would be nice if we could “do one thing at a time” and “do it well,” but that is simply not how the world works. The human body performs a great variety of operations in parallel, or as we will say throughout this chapter, concurrently. Respiration, blood circulation and digestion, for example, can occur concurrently. All of the senses—seeing, touching, smelling, tasting and hearing—can all occur concurrently. An automobile can be accelerating, turning, air conditioning and playing music concurrently. Computers, too, perform operations concurrently. It is common today for desktop personal computers to be compiling a program, printing a file and receiving e-mail messages over a network concurrently.
Concurrency is important in our lives. Ironically, though, most programming languages do not enable programmers to specify concurrent activities. Rather, programming languages generally provide only a simple set of control structures that enable programmers to perform one action at a time then proceed to the next action after the previous one is finished. The kind of concurrency that computers perform today normally is implemented as operating systems “primitives” available only to highly experienced “systems programmers.”
The Ada programming language developed by the United States Department of Defense made concurrency primitives widely available to defense contractors building command and control systems. But Ada has not been widely used in universities and commercial industry.
Java is unique among popular general-purpose programming languages in that it makes concurrency primitives available to the applications programmer. The programmer specifies that applications contain threads of execution, each thread designating a portion of a program that may execute concurrently with other threads. This capability, called multithreading, gives the Java programmer powerful capabilities not available in C and C++, the languages on which Java is based. C and C++ are called single-threaded languages.
Chapter 15 Multithreading 839
[Note: On many computer platforms, C and C++ programs can perform multithreading by using system specific code libraries.]
Software Engineering Observation 15.1
Unlike many languages that do not have built-in multithreading (such as C and C++) and must therefore make calls to operating system multithreading primitives, Java includes multithreading primitives as part of the language itself (actually in classes Thread, ThreadGroup, ThreadLocal and ThreadDeath of the java.lang package). This encourages the use of multithreading among a larger part of the applications-programming community.
We will discuss many applications of concurrent programming. When programs download large files such as audio clips or video clips from the World Wide Web, we do not want to wait until an entire clip is downloaded before starting the playback. So we can put multiple threads to work: One that downloads a clip and another that plays the clip so that these activities, or tasks, may proceed concurrently. To avoid choppy playback, we will coordinate the threads so that the player thread does not begin until there is a sufficient amount of the clip in memory to keep the player thread busy.
Another example of multithreading is Java’s automatic garbage collection. In C and C++, the programmer is responsible for reclaiming dynamically allocated memory. Java provides a garbage collector thread that reclaims dynamically allocated memory that the program no longer needs.
Testing and Debugging Tip 15.1
In C and C++, programmers must provide explicit statements that reclaim dynamically allocated memory. When memory is not reclaimed (because a programmer forgets to do so, because of a logic error or because an exception diverts program control), this results in an all-too-common error called a memory leak that can eventually exhaust the supply of free memory and may cause premature program termination. Java’s automatic garbage collection eliminates the vast majority of memory leaks, that is, those that are due to orphaned (unreferenced) objects.
Java’s garbage collector runs as a low-priority thread. When Java determines that there are no longer any references to an object, it marks the object for eventual garbage collection. The garbage-collector thread runs when processor time is available and when there are no higher priority runnable threads. However, the garbage collector will run immediately when the system is out of memory.
Performance Tip 15.1
Setting an object reference to null marks that object for eventual garbage collection (if there are no other references to the object). This can help conserve memory in a system in which a local variable that refers to an object does not go out of scope because the method in which it appears executes for a lengthy period.
Writing multithreaded programs can be tricky. Although the human mind can perform many functions concurrently, humans find it difficult to jump between parallel “trains of thought.” To see why multithreading can be difficult to program and understand, try the following experiment: open three books to page 1. Now try reading the books concurrently. Read a few words from the first book, then read a few words from the second book, then read a few words from the third book, then loop back and read the next few words from the first book, and so on. After a brief time, you will appreciate the challenges of multithreading: switching between books, reading briefly, remembering your place in each
840 |
Multithreading |
Chapter 15 |
book, moving the book you are reading closer so you can see it, pushing books you are not reading aside, and amidst all this chaos, trying to comprehend the content of the books!
Performance Tip 15.2
A problem with single-threaded applications is that lengthy activities must complete before other activities can begin. In a multithreaded application, threads can share a processor (or set of processors), so that multiple tasks are performed in parallel.
Although Java is perhaps the world’s most portable programming language, certain portions of the language are nevertheless platform dependent. In particular, there are differences among the first three Java platforms implemented, namely the Solaris implementation and the Win32 implementations (i.e., Windows-based implementations for Windows 95 and Windows NT).
The Solaris Java platform runs a thread of a given priority to completion or until a higher priority thread becomes ready. At that point preemption occurs (i.e., the processor is given to the higher priority thread while the previously running thread must wait).
In the 32-bit Java implementations for Windows 95 and Windows NT, threads are timesliced. This means that each thread is given a limited amount of time (called a time quantum) to execute on a processor, and when that time expires the thread is made to wait while all other threads of equal priority get their chances to use their quantum in roundrobin fashion. Then the original thread resumes execution. Thus, on Windows 95 and Windows NT, a running thread can be preempted by a thread of equal priority; whereas, on the Solaris implementation, a running Java thread can only be preempted by a higher priority thread. Future Solaris Java systems are expected to perform timeslicing as well.
Portability Tip 15.1
Java multithreading is platform dependent. Thus, a multithreaded application could behave differently on different Java implementations.
15.2 Class Thread: An Overview of the Thread Methods
In this section, we overview the various thread-related methods in the Java API. We use many of these methods in live-code examples throughout the chapter. The reader should refer to the Java API directly for more details on using each method, especially the exceptions thrown by each method.
Class Thread (package java.lang) has several constructors. The constructor
public Thread( String threadName )
constructs a Thread object whose name is threadName. The constructor
public Thread()
constructs a Thread whose name is "Thread-" concatenated with a number, like
Thread-1, Thread-2, and so on.
The code that “does the real work” of a thread is placed in its run method. The run method can be overridden in a subclass of Thread or it may be implemented in a Runnable object; Runnable is an important Java interface that we study in Section 15.10.
A program launches a thread’s execution by calling the thread’s start method, which, in turn, calls method run. After start launches the thread, start returns to its