610 likes | 684 Views
Object-Oriented Programming Threads. Kirk Scott. Threads. 29.1 Background 29.2 Example. 29.1 Background. What are Threads?. Before trying to explain what the term thread refers to in Java programming, it is helpful to review some background concepts.
E N D
Object-Oriented ProgrammingThreads Kirk Scott
Threads • 29.1 Background • 29.2 Example
What are Threads? • Before trying to explain what the term thread refers to in Java programming, it is helpful to review some background concepts. • One of these concepts is the order of execution of instructions in a program. • This should be familiar. • The other concept is concurrency, which may not be.
A program consists of a structured set of instructions where the order they come in is meaningful. • The program may contain ifs and loops, which mean that the instructions aren’t necessarily executed sequentially in the order that they appear in the program. • However, the logic of the program dictates that for any given program run, the instructions are executed in a well-defined order.
Concurrency refers to the following idea. • In a modern computer with a modern operating system, more than one active program may exist at the same time. • These co-existing programs don’t run simultaneously. • Only one program can run at a time.
However, the programs run concurrently. • This means that part of the sequence of instructions from one program is run, then part of a sequence from another, and so on. • It is not necessary for one program to run from beginning to end before the next one can start. • The programs alternate execution, interleaving subsequences of their instructions.
In the scenario described above, two completely different programs may be running concurrently. • It is also possible to have more than one separate execution sequence through the same program running concurrently. • It’s “as if” there were two copies of the same program—but it’s not necessary to make a copy.
Two execution sequences can simply share the same program code, and the system keeps track of which instruction in the code each sequence is on at any given time. • Separate execution sequences sharing the same code are known as threads.
This term is a metaphor. • The lines of code in a program are like the yarn that runs crosswise through woven cloth (known as the weft or woof). • The sequences of execution are like the threads that run lengthwise through the cloth (known as the warp). • Separate paths through the lines of code/yarn can be traced by following more than one thread.
Synchronization and Concurrency Control • By definition, threads share program code. • Complexity arises when two different threads also share access to common data, with the potential to both read and modify it concurrently. • Dealing with this is known generically as concurrency control.
In Java it is dealt with using a concept known as synchronization and the key word synchronized. • If threaded code has shared data and concurrency control is not implemented, the code is said not to be thread safe. • The compiler can recognize this condition and generate warnings and error messages indicating it.
Threading is an advanced topic that is usually covered in an operating systems course. • It is not covered completely here. • In particular, this section will not cover concurrency control or its solutions. • This unit is designed only to introduce the syntax for creating multiple threads in Java.
It is not necessary for threaded code to share resources, and the example code is designed to illustrate threading without shared resources. • One part of the first programming assignment involves threading, but it does not require concurrency control. • As long as you do not write code which shares resources, you can write simple threaded code without problems.
Making Thread Instances • Java has a class named Thread which makes it possible to write threaded code. • Syntactically, there are two different ways of accomplishing this. • Here is a brief review of the first:
Extending the Thread Class • 1. In an application, write a class that extends the system supplied Thread class. • 2. Override the run() method in that class. • The run() method will contain the executable thread code for your application • 3. Construct one or more instances of your class. • 4. Call the start() method on the object(s).
5. The objects of that class, and the code in the class definition, are threaded. • The number of objects which are constructed and have the start() method called on them defines the number of concurrent threads which will run when the program is executed.
Notice that this is an example of a callback sequence • The user program calls an inherited method that is not seen, and never directly calls the overridden method that is visible in the code.
The start() method allocates memory for and initializes a new thread in the Java system. • It then calls the object’s run() method. • If the user code calls the run() method directly, initialization does not occur.
The approach to implementing threading described above is straightforward and will work in many cases. • Keep in mind that it is only possible for a given class to extend one other class. • Java doesn’t support multiple inheritance.
Creating Instances of the Thread Class • If the class to be threaded is already a subclass of another class, extending the Thread class is not possible. • For example, suppose you would like to write a threaded applet. • The applet class will have to extend the JApplet class and it won’t be possible to also extend the Thread class.
Instead of multiple inheritance, Java supports interfaces, and it is also possible to implement threaded code by implementing the Runnable interface. • Here is a brief review of this second approach to writing threaded code:
1. In an application, write a class that implements the system supplied Runnable interface. • 2. Implement the run() method specified by the interface in the class. • Again, the run() method will contain the application specific thread logic
3. Construct one or more instances of that class. • Since only the run() method is specified in the interface, note that the interface alone does not provide all of the machinery necessary for constructing and starting threads.
4. For each object of the given class, construct a thread by calling the constructor Thread() and passing it a reference to the object. • 5. Call the start() method on the instances of the Thread class so created.
As usual, there is much more information on this topic in the Java API documentation of the Thread class and the Runnable interface. • For what it’s worth, the Thread class itself implements the Runnable interface. • This accounts for why the Thread class contains a run() method.
The Thread class also has more than one constructor, making it possible to construct threads for runnable objects that are passed in. • The whole scheme falls apart if the programmer does not implement a run() method in the given class.
Note two points which may be obvious: • 1) The constructors for the runnable class itself will be application dependent. • What they contain does not depend on the constructor for the Thread class.
2) In this whole discussion, the contents of the run() method have not been discussed. • What the run() method does is entirely application dependent. • The run() method contains the code which is to be run concurrently by the different threads.
Which Approach is Better? • Consider the general description of the meaning of inheritance • A subclass is a kind of, or more specific kind of its superclass • Observe that an application specific class that is threaded is not a kind of thread • Its run method does something, and multiple threads may be executing through that method
So from a philosophical viewpoint, the first approach, of extending the Thread class is “wrong” • However, in many cases it is the simpler approach, so the Java API developers provided it • Constructing threads and passing in the objects is the more flexible and philosophically agreeable approach • It is also marginally more complicated
MiscThread • This example shows how multiple subframes can be added to a running application where each subframe has its own thread of execution. • Each of the subframes has two registers and the threads for the subframes continually swap the contents of the registers. • Because multiple subframes will exhibit the same behavior at the same time, concurrent execution is made visually apparent.
The Thread class contains a static, void method named sleep() • This is what the API has to say about it: • sleep(long millis) Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds. • Putting a call to sleep() in the run() method for the example can slow the register swapping down enough that it is easy to see.
Three screenshots are shown on the following overheads. • In the main frame there are File menu options to make a subframe or exit. • In the subframes there are registers, and in the subframe menu there are File options to restart or close the subframe. • The idea is that multiple subframes can be opened and each of these subframes will concurrently swap its register contents
The UML diagram for the application follows. • The critical things to note are the following: • The MiscThreadFrame can have 0 or more instances of the MiscThreadSubFrame and the MiscThreadSubFrame class implements the runnable interface. • In other words, overall, the application may have many threads, each embodied in a separate subframe.
The code for the MiscThreadSubFrame class will be shown below. • Here is the declaration of the threaded class in the MiscThread example: • class MiscThreadSubFrame extends JFrame implements Runnable • (It is declared this way without an access modifier simply because all of the classes for the example were stored in a single .java file.)
The key point is that the subframe class is implemented in a form that leads to threads. • MiscThreadSubFrame implements the Runnable interface. • It would not be possible for it to extend the Thread class because it already extends the JFrame class. • The subframes contain various components just as in non-threaded frames.
Some of the components are graphical representations of elements of the application. • Other components contain instructions implementing program logic. • In particular, the run() method, required by the implementation of the Runnable interface, contains that code which is concurrently run by different threads of the subframe class.
In the run() method the contents of the registers belonging to the frame are swapped. • Observe that each subframe has its own registers. • Individual subframes do not share access to components of other subframes.
This means that even though the threads execute concurrently in the run() method, there are no potential concurrency problems and no need for concurrency control in the application. • The code for the subframe class is shown beginning on the following overhead
class MiscThreadSubFrame extends JFrame implements Runnable • { • private MiscThreadPanelmyPanel; • private final int FRAMEW = 250; • private final int FRAMEH = 250;
public MiscThreadSubFrame() • { • setTitle("MiscThread Frame"); • setSize(FRAMEW, FRAMEH); • myPanel = new MiscThreadPanel(); • Container contentPane = getContentPane(); • contentPane.add(myPanel, "Center"); • addWindowListener(new WindowCloser());
JMenuBarmenuBar = new JMenuBar(); • setJMenuBar(menuBar); • JMenufileMenu = new JMenu("File"); • menuBar.add(fileMenu); • JMenuItemrestartItem = new JMenuItem("Restart"); • fileMenu.add(restartItem);
RestartListenermyRestartListener = new RestartListener(); • restartItem.addActionListener(myRestartListener); • JMenuItemcloseItem = new JMenuItem("Close"); • fileMenu.add(closeItem); • CloseListenermyCloseListener = new CloseListener(); • closeItem.addActionListener(myCloseListener); • }
/* Here is the run() method. This tells you that MiscThreadSubFrame is a threaded class. */ • public void run() • { • while(true) • { • try • { • Thread.sleep(100); • } • catch(InterruptedException e) • { • System.out.println("InterruptedException: " + e); • } • myPanel.getRegisterA().swapRegisterContents(myPanel.getRegisterB()); • } • }