The Java platform was designed from the start to be a multithreaded
environment. While your main program is executing, other tasks like
garbage collection and event handling are done in the background.
Mentally, you can think of these other tasks as threads. They happen to
be system-managed threads, but nonetheless, they are threads. Threads
enable you to define isolated tasks that happen independently of each
other. The system then swaps tasks in and out of the CPU so that
(externally) it appears they are all running simultaneously.
When you need to do multiple tasks in your own program, you, too,
can work with multiple threads. These threads can be ones you create
yourself, or you can interact with the system threads.
You do these multiple tasks using several different classes and interfaces:
java.util.Timer class
javax.swing.Timer class
Thread class
Runnable interface
For simple tasks that typically need to repeat, you can work with the java.util.Timer
class to say "Do this task every half second." Keep in mind that most
system routines work with milliseconds. A half second is 500
milliseconds.
The task you want the Timer to perform is defined in a java.util.TimerTask instance, where its run method contains the task to perform. This is demonstrated in the Hi class, where the String "Hi" is printed to the console repeatedly, until you press the Enter key.
import java.util.*;
public class Hi { public static void main(String args[]) throws java.io.IOException { TimerTask task = new TimerTask() { public void run() { System.out.println("Hi"); } }; Timer timer = new Timer(); timer.schedule(task, 0, 500); System.out.println("Press ENTER to stop"); System.in.read(new byte[10]); timer.cancel(); } }
The way the Java Runtime Environment (JRE) works is that as long as
there is a thread running, the program won't exit. So, once cancel is
called, there are no other user threads running and the program exits.
There are some system threads running, like the garbage collector.
These system threads are also called daemon threads. The existence of
daemon threads does not prevent the runtime environment from shutting
down; Only non-daemon threads prevent that.
The javax.swing.Timer class works similarly to the java.util.Timer class, with a couple of differences of note. First, the task to run is defined by an implementation of the ActionListener interface. Second, the task executes within the event-handling thread, not outside of it like the java.util.Timer class. This is important because of how the Swing component set was designed.
If you aren't familiar with Swing, it is the set of graphics components available to Java programs. Swing was designed to be what is called single-threaded. That means that all access to the internal contents of the Swing
classes must be done within a single thread. That specific thread is
the event-handling thread. So, for example if you wanted to change the
text of a label component, you couldn't just call the setText method of JLabel. Instead, you would have to make sure that the setText call happens in the event-handling thread, and that is where the javax.swing.Time class comes in handy.
To demonstrate this second case, the following program displays the
value of an increasing counter. Every half second the counter value is
increased and the new value is displayed.
public class Count { public static void main(String args[]) { JFrame frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Container contentPane = frame.getContentPane(); final JLabel label = new JLabel("", JLabel.CENTER); label.setFont(new Font("Serif", Font.PLAIN, 36)); contentPane.add(label, BorderLayout.CENTER); ActionListener listener = new ActionListener() { int count = 0; public void actionPerformed(ActionEvent e) { count++; label.setText(Integer.toString(count)); } }; Timer timer = new Timer(500, listener); timer.start(); frame.setSize(300, 100); frame.show(); } }
The program above produces the following:
In cases where there isn't a simple repeating task to be done, the java.lang.Thread class comes into play. It allows you to control the raw functionality yourself. By creating a subclass of Thread,
you can have the system go off and do a long-running task, like reading
a file from over the network, without blocking the execution of the
rest of your program. That long running task would be defined in the
run method.
The run method used by Thread and TimerTask is actually part of an interface: java.lang.Runnable. While you could always subclass Thread
to define the task to be done, if you aren't adding any behavior to the
subclass (besides the task to be done) the more appropriate way to
design the system is to define the task to be done in an implementation
of the Runnable interface. Then, you pass the implementation to the Thread constructor. And, when you start the thread up, that Runnable is what is executed.
The second way is to subclass Thread and implement the run method in the subclass, or implement the run method in a class that implements Runnable and pass that implementation on to the Thread constructor.
You may ask yourself what is the difference. The Java programming
language only supports single inheritance. If your design calls for a
different superclass besides Thread, you can have your class implement Runnable, and it will have its task to execute. Otherwise, you subclass Thread to define its own run method, adding no particular set of operations in the process.
For this third case of subclassing Thread, the
following program creates a new thread to count the number of
characters in a particular URL whose value is passed in from the
command line. While that is going on, the fourth case of implementing Runnable is demonstrated, printing out a repeated message. Notice in this latter case of implementing Runnable, you must provide the code to repeat the message. You have to both sleep for the allotted time and do the action. Compare that to the use of Timer,
in both cases. The final piece of the program has you read a line from
the command to trigger the program ending. Notice that while the system
is reading from the URL and printing the message, you can always press
Enter to end the program.
import java.io.*; import java.net.*;
public class Both { public static void main(String args[]) { final String urlString = args[0]; final String message = args[1]; Thread thread1 = new Thread() { public void run() { try { URL url = new URL(urlString); URLConnection connection = url.openConnection(); InputStreamReader isr = new InputStreamReader( connection.getInputStream()); BufferedReader reader = new BufferedReader(isr); int count = 0; while (reader.read() != -1) { count++; } System.out.println("Size is : " + count); reader.close(); } catch (MalformedURLException e) { System.err.println("Bad URL: " + urlString); } catch (IOException e) { System.err.println("I/O Problems"); } } }; thread1.start(); Runnable runnable = new Runnable() { public void run() { while(true) { System.out.println(message); try { Thread.sleep(500); } catch (InterruptedException e) { } } } }; Thread thread2 = new Thread(runnable); thread2.start(); try { System.out.println("Press ENTER to stop"); System.in.read(new byte[10]); } catch (IOException e) { System.out.println("I/O problems"); } System.exit(0); } }
While there are many ways of working with threads, which technique
you use is up to you and your circumstances. While you usually don't
have to learn everything about the Java programming language and its
core libraries to become a productive Java programmer, threading is an
exception. The sooner you can understand how threads work and how to
use them, the sooner you'll come to understand how Java programs work
and interact.
A boolean value is a primitive data type that has a value of either true or false. Boolean statements allow you to consider several conditions in one programming decision. To determine if conditions are true or false, boolean expressions frequently use the following operators:
&& to mean AND
|| to mean OR
! to mean NOT
^ to mean XOR
For example, in a program to determine overtime pay, the application
must first determine whether the employee's work hours exceeded 40 hours for a particular week and for a particular type of job position:
The problem above is stating that if the hours worked are more than 40, and the job position is a sales clerk or a stock person, then print the statement, "Employee receives overtime pay." Otherwise, print the statement, "Employee receives regular pay."
Sometimes you may want to declare boolean variables first, then use them in a boolean expression to test conditions:
if(isSaturday && isDayLight) System.out.println("Go play at the beach"); if (isSaturday && !isDayLight) System.out.println("Sleep until Sunday.");
In the example above, the first boolean variable isSaturday is true only if a String Saturday is returned. The second boolean variable isDayLight defines the condition for daylight, and returns true only if these hourly conditions are met.
Pop-up dialog boxes are useful GUI components that can be used to alert
users to problems, request information, or provide instruction. The
Swing API provides a JOptionPane
class that allows you to create simple dialog boxes by calling a static
method, or create more elaborate dialogs containing text fields and
buttons.
There are four basic types of JOptionPane dialog boxes:
Input dialog
Confirm dialog
Message dialog
Option dialog
You can create JOptionPane dialog boxes either by calling one of the JOptionPane constructors, or by calling one of the JOptionPane static methods:
showConfirmDialog: Ask a confirming question, like Yes/No/Cancel.
showInputDialog: Prompt for input.
showMessageDialog: Inform the user that something has happened.
showOptionDialog: A combination of the above three.
The JOptionPane objects are not standalone containers. Instead, they exist inside a JDialog or JInternalFrame object that the static methods create and associate automatically.
When an application runs and the dialog pops up, unless a thread is
implemented, no other action can be taken within the application until
the dialog is dealt with, either by entering information, clicking a
button, or closing the dialog box.
To create a message dialog that warns the user that the requested file doesn't exist, for instance, call the showMessageDialog static method:
JOptionPane.showMessageDialog(null, "Requested file cannot be found.", null, JOptionPane.ERROR_MESSAGE );
or a dialog to confirm information:
JOptionPane.showConfirmDialog(null, "Do you want to Exit?", null, JOptionPane.YES_NO_OPTION );
JOptionPane dialog boxes serve many useful purposes from collecting data from the user to providing warnings and information.
Create a program that displays a number in the middle of the screen, and has four buttons.
The first button causes the number to increment its value every
half second.
The second button causes the number to decrement its value every
half second. The value can be incrementing or decrementing
in one direction at a time.
The third button causes the incrementing/decrementing behavior to
stop.
For most Java development, you need the class libraries, compiler,
tools, and runtime environment provided with the Java 2, Standard
Edition (J2SE) development kit.
Subscribe to the following newsletters for the latest information about technologies and products in other Java platforms:
- Core Java Technologies Newsletter. Learn about new products,
tools, resources, and events of interest to developers
working with core Java technologies.
- Wireless Developer Newsletter. Learn about the latest
releases, tools, and resources for developers working on
wireless and Java Card technologies and applications.
- Core Java Technologies Tech Tips (formerly JDC Tech Tips)
Get expert tips, sample code solutions, and techniques for
developing in the Java 2 Platform, Standard Edition (J2SE)
You can subscribe to these and other JDC publications on the JDC Newsletters and Publications page