470 likes | 595 Vues
Object-Oriented Programming (Java), Unit 29. Kirk Scott. Threads. 29.1 Background 29.2 Example. 29.1 Background. 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 Programming (Java), Unit 29 Kirk Scott
Threads • 29.1 Background • 29.2 Example
29.1 Background • 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 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. • In short, instructions are executed one after the other in some sequence.
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.
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. • The section is designed only to introduce the syntax for creating multiple threads.
It is not necessary for threaded code to share resources, and the example in the section is designed to illustrate threading without shared resources. • One part of the final project assignment may involve threading, but it is only necessary to accomplish what is done in the example. • As long as you do not write code which shares resources, you can write simple threaded code without problems.
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:
1. In an application, write a class that extends the system supplied Thread class. • 2. Override the run() method in that class. • 3. Construct one or more instances of that 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 yet another situation where 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.
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. • 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.
MiscThread • This example shows how multiple subframes can be added to a running application where each subframe has its own thread of execution. • These subframes have two register and all the application does is continually swap their contents. • Because multiple subframes will exhibit the same behavior at the same time, concurrent execution is made visually apparent.
A sleep() call is put in the run() method in order to slow the swapping down enough that it is easy to see. • If you need a refresher on sleeping, refer to the examples in Unit 5. • Three screenshots are shown. • In the main frame there are File menu options to make a subframe or exit. • In the subframes there are registers, and in the menu there are File options to restart or close the subframe.
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 is shown below. Here is the declaration of the threaded class in the MiscThread example: • class MiscThreadSubFrame extends JFrame implements Runnable
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.
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); • }
public void run() • { • while(true) • { • try • { • Thread.sleep(100); • } • catch(InterruptedException e) • { • System.out.println("InterruptedException: " + e); • } • myPanel.getRegisterA().swapRegisterContents(myPanel.getRegisterB()); • } • }
private class WindowCloser extends WindowAdapter • { • public void windowClosing(WindowEvent event) • { • dispose(); • } • }
private class RestartListener implements ActionListener • { • public void actionPerformed(ActionEvent event) • { • Container contentPane = getContentPane(); • contentPane.remove(myPanel); • myPanel = new MiscThreadPanel(); • contentPane.add(myPanel, "Center"); • setVisible(true); • } • }
private class CloseListener implements ActionListener • { • public void actionPerformed(ActionEvent event) • { • dispose(); • } • }
Here is the code for the MakeSubFrameListener which is implemented as an inner class of the MiscThreadFrame class. • By selecting the option in the menu which has this listener attached to it, new subframes/threads come into existence in the application. • As noted above, the MiscThreadSubFrame class implements the Runnable interface rather than extending the Thread class.
As a result, the code in this listener uses the second approach described in the previous section for creating subframe threads. • An instance of a frame is created, and this is passed as a parameter to the Thread() constructor when the corresponding thread is created. • The code is written so that the new frames do not appear in exactly the same location when they are created. • They are offset diagonally so they don’t completely cover each other up.
private class MakeSubFrameListener implements ActionListener • { • public void actionPerformed(ActionEvent event) • { • MiscThreadSubFramemyframe = new MiscThreadSubFrame(); • myframe.setLocation(subFrameLocation, subFrameLocation); • if(subFrameLocation >= 500) • { • subFrameLocation = 50; • } • else • { • subFrameLocation += 50; • } • Thread mythread = new Thread(myframe); • mythread.start(); • myframe.setVisible(true); • } • }
Do not forget the following code in the Fall of 2009 CS 202 final project folder: • WariV12OKOriginal.java • WariV12BetterModified.java • WariV12BestModifiedAgain.java • These versions of the final project program show the progression to an application that has a minimum of passing references of containing objects to contained objects
This progression two aspects: • Making the board have a panel instead of vice-versa • Making the cup class an inner class of the board class • Consider showing the code in class (as a unit 30 powerpoint, for example) without posting it as a .java or .doc unit notes file which could be downloaded and copied