As concurrent Java applications are going to be accumulated, the develop- ... ment of concurrent Java software will become an im- portant issue. ProgramĀ ...
Multithreaded Dependence Graphs for Concurrent Java Programs Jianjun Zhao
Department of Computer Science and Engineering Fukuoka Institute of Technology 3-10-1 Wajiro-Higashi, Higashi-ku, Fukuoka 811-02, Japan zhao@cs. t.ac.jp Abstract
Understanding program dependencies in a computer program is essential for many software engineering activities including program slicing, testing, debugging, reverse engineering, and maintenance. In this paper, we present a dependence-based representation called multithreaded dependence graph, which extends previous dependence-based representations, to represent program dependencies in a concurrent Java program. We also discuss some important applications of a multithreaded dependence graph in a maintenance environment for concurrent Java programs. 1
Introduction
Java is a new object-oriented programming language and has achieved widespread acceptance because it emphasizes portability. Java has multithreading capabilities for concurrent programming. To provide synchronization between asynchronously running threads, the Java language and runtime system uses monitors. Because of the nondeterministic behaviors of concurrent Java programs, predicting, understanding, and debugging a concurrent Java program is more dicult than a sequential object-oriented program. As concurrent Java applications are going to be accumulated, the development of techniques and tools to support understanding, debugging, testing, maintenance, complexity measurement of concurrent Java software will become an important issue. Program dependencies are dependence relationships holding between program statements in a program that are implicitly determined by the control ows and data
ows in the program. Intuitively, if the computation of a statement directly or indirectly aects the computation of another statement in a program, there might exist some program dependence between the statements. Program dependence analysis is the process to determine the program's dependencies by analyzing the control ows and data ows in the program. Many compiler optimizations and program analysis and testing techniques rely on program dependence information, which is topically represented by a dependencebased representation (DBR), for example, a program de-
pendence graph (PDG) [7, 13]. The PDG, although originally proposed for compiler optimizations, has been used for various software engineering activities including program slicing, debugging, testing, maintenance, and complexity measurements [1, 2, 6, 11, 16, 17]. For example, program slicing, a decomposition technique that extracts program statements related to a particular computation, is greatly bene t from a PDG on which the slicing problem can be reduced to a vertex reachability problem [16] that is much simpler than its original algorithm [23].
DBRs were originally constructed for procedural programs. Recently, as object-oriented software become popular, researchers have applied DBRs to objectoriented programs to represent various object-oriented features such as classes and objects, class inheritance, polymorphism and dynamic binding [4, 5, 12, 14, 15], and concurrency [24, 26]. (for detailed discussions, see related work section). However, the existing DBRs for object-oriented software can not be applied to concurrent Java programs straightforwardly due to the speci c features of Java concurrency model. In order to represent the full range of concurrent Java program, we must extend the existing DBRs for representing concurrent Java programs. In this paper we present a DBR called multithreaded dependence graph, which extends previous DBRs, to represent various types of dependencies in a concurrent Java program. The multithreaded dependence graph of a concurrent Java program consists of a collection of thread dependence graphs each representing a single thread in the program, and some special kinds of dependence arcs to represent thread interactions between dierent threads. Finally, we discuss some important applications of a multithreaded dependence graph in a maintenance environment for concurrent Java programs. The rest of the paper is organized as follows. Section 2 brie y introduces the concurrency model of Java. Section 3 discusses some related work and explains why existing DBRs can not be used to represent concurrent Java programs correctly. Section 4 presents the mul-
tithreaded dependence graph for concurrent Java programs. Section 5 discusses some applications of the graph. Concluding remarks are given in Section 6. 2
Concurrency Model in Java
Java supports concurrent programming with threads through the language and the runtime system. A thread is a single sequential ow of control within a program. It is similar to a sequential program in the sense that each thread also has a start, a sequence of execution, and a stop and at any given time during the runtime of the thread, there is a single point of execution. However, a thread itself is not a program because it can not run independently, rather, it can only run within a program. Programs that has multiple synchronous threads are called multithreaded programs topically. Java provides a Thread class library, that de nes a set of operations on one thread, like start(), stop(), join(), suspend() and resume(). Java uses shared memory to support communication among threads. Objects shared by two or more threads are called condition variables, and the access on them must be synchronized. The Java language and runtime system support thread synchronization through the use of monitors. In general, a monitor is associated with a speci c data item (a condition variable) and functions as a lock on that data. When a thread holds the monitor for some data item, other threads are locked out and cannot inspect or modify the data. The code segments within a program that access the same data from within separate, concurrent threads are known as critical sections. In Java, you may mark critical sections in your program with the synchronized keyword. Java provides some methods of Object class, like wait(), notify(), and notifyall() to support synchronization among dierent threads. Using these operations and different mechanism, threads can cooperate to complete a valid method sequence of the shared object. Any Java program begins its execution from the main() method. The thread of execution of the main method is the only thread that is running when the program is started. Execution of all other threads is started by calling their start() methods, which begins execution with their corresponding run() methods. Figure 1 shows a simple concurrent Java program that implements the Producer-Consumer problem. The program creates two threads Producer and Consumer. The Producer generates an integer between 0 and 9 and stores it in a CubbyHole object. The Consumer consumes all integers from the CubbyHole as quickly as they become available. Threads Producer and Consumer in this example share data through a common CubbyHole object. However, to execute the program correctly, the following condition must be satis ed, i.e., the Producer
ce1 2 3 e4 s5 s6 7 te8 s9 s10 s11 s12 s13 s14 15 16 17 ce18 19 20 e21 s22 s23 24 te25 s26 s27 s28 s29 s30 s31 s32 33 34 35 ce36 37 s38 me39 s40 s41 42 s43 s44 s45 46 me47 s48 s49 50 s51 s52 s53 54 55 ce56 me57 s58 s59 s60 s61 s62 63 64
class Producer extends Thread { private CubbyHole cubbyhole; private int number; public Producer(CubbyHole c, int number) { cubbyhole = c; this.number = number; } public void run() { int i=0; while (i