Alfonse, Your Java Is Ready! - Semantic Scholar

4 downloads 173 Views 559KB Size Report
For example, here is a Java server monitor for the five dining philosopher .... The Sun Microsystems JDK for Windows 95 uses native threads and so Java ...
.

“Alfonse,

Your Java Is Ready!“’

Stephen J. Hartley Math and Computer Science Department Drhxel University, Philadelphia, PA 19104 (215) 895-2678 . mailto:[email protected] . ming books, for, example [AndSl, B&90, BD93]. This ,paper describes, and evaluates the features Java has supporting concurrent programming for operating systems and other courses. To handle what is missing (message passing) and to wrap a rendezvous interface around sockets, the author has written a concurrent programming library of classes,available at ftp://ftp.mcs.drexel.edu/pub/ shertley/concProgsJava.zip and http://www.mcs. drexel.edu/“shartley/ConcProgJava/index.html.

Abstract

L L i Is Java suitable for teaching concurrent programming? This paper describes the features Java has for this, how well they work, and what is missing. The author has written a library of classes,also described here, to provide the missing features. Supplemented with these classes,Java works well as the concurrent programming language in operating systems and related courses. lntrodktion

What Java Has The abundance of hype Java [AG96, .CH96, Sun971 receives should not’ distract us from the fact ‘that it has many excellent features for teaching sequential programming: object-oriented, no explicit pointers and no pointer arithmetic, automatic garbage collection and no memory leaks, strong typing, platform independence, and many compiler and run-time checks. The development kit (JDK) for the language comes with ,a rich collection of class libraries (AI%) for data structures, IO, networking, remote procedure calls, and graphics. Since threads are built-in, Java can be used for concurrent programming and developing multithreaded applications. The question remains, however, whether Java is suitable-as the concurrency platform in operating systems and related coursesto give students practice and experience [BC96] in concurrent programming. Besides supporting multiple threads, a language for teaching concurrent programming should have semaphores and monitors for synchronizing threads sharing the same address space, and messagepassing capabilities so threads in different address spaces(perhaps on different computers) can communicate. Other desirable features are the rendezvous and remote procedure calls for clientserver style programming. These programming tools are described in many operating systems texts, such as [DeiSO,SG94, Sta95, TW97], and concurrent program-

Java comes with a Thread class that has many useful methods: start, stop, yield the CPU, suspend execution, resume execution, sleep for some number of milliseconds, and join someother thread when it terminates. Since all threads started in the same Java virtual machine (JVM) share the same’addressspace, they’all have accessto public variables and there is a need for mutual exclusion to avoid lost updates and race conditions. Threads also need to block if conditions are not right to proceed until they are signaled by another thread, called event or condition synchronization. Note that suspend and resume cannot be used for condition synchronization because a context switch might occur after a thread has decided conditions are not right to proceed but before it has called suspend; the thread might then miss alater resume intended for it. Students must be discouraged from succumbing to this temptation. For mutual exclusion and synchronization, Java provides the monitor as its,built-in primitive. A Java monitor has synchronized in all its public method declarations. The wait, notify, and notifyAl methods are used for condition synchronization. The only signaling discipline available in Java monitors is signal-andcontinue. There are two important properties of this. (1) Since the signaled thread does not get priority to reenter the monitor, the’condition that resulted in the signal may no longer be true; other threads may have “barged” in ahead of it. (2) Since the signaling thread is not required to leave the monitor immediately after signaling, it can change the state of the monitor after signaling, possibly negating the condition for which the signaled thread is waiting, The implication of these two

Permissionto makedigitalhard copiesof all or part of this material for personalor classroomuseis grantedwithout fe providedthat the copies arenot madeor distributedfor profit or cnmmercialadvantage,the copyright notice,thetitle ofthe publicationandits dateappear,andnoticeis ‘on ofthe ACM, Inc. To copy otherwise, giventhat copyrightis by pemuss~ to republish,to poston serversor to redistribute-to lists,requiresspecific permissionantior fee.

SIGSCE98 AtlsntaGA USA Copyright 1998 0-89791-994-7/98/2..%5.00 247

properties is that threads should use a loop while

while (state[i] != EATING) try { wait(); catch (InterruptedException e) I)

( ! condition) wait 0 ;

3

instead of an if check. if

public synchronized void putForks(int state[i] = THINKING; testCleft(i test(right(i)); notifyAll();

( ! condition) wait 0 ;

This needs to be clearly explained to students. Another important property of Java monitors is that each one has just a single anonymous condition variable; a signal cannot be directed to’any particular queue of threads waiting for a specific condition. Either one random waiting thread is released with notify or all waiting threads with notifyAll. The safest programming practice is to wake up all threads with notif yAl1 before leaving the monitor, particularly if its state has been changed. Thus, monitor methods should have the pattern public synchronized type method -( ... while ( ! condition) wait 0 ; ... notifyhllo,; ;,, ; 3 For example, here is a Java server monitor for the five dining philosopher threads in that well-known operating systems synchronization problem. Note the use of while waiting loops and not if yAl1. ?,

i)
( I

In order to execute the statements inside a synchronized block, the thread must first obtain the lock on the object pointed to by object. Each Java object has an associated lock, so any object can be used for object in a synchronized block. When an object’s lock is released by a thread exiting a synchronized block, the virtual machine choosesa thread at random from those waiting, if any, to acquire the lock., . Synchronized blocks can be used to enforce mutual exclusion during accessto shared data by a collection of threads. shared by the threads: Object mutex = neir ObjectO; in each thread:“’ synchronized (mutex) -f. critical section; 3

class DiningServer,
I

3

3

/

is an abbreviation for

private final int left(int i) < return (numPhils+i-l)%numPhils; private final: int rightcint < return (i+l)%nuuPhils;

3

i> 3

method (.‘. .> ( synchronized (this)

type

3

i (

... 3

' ,

private void test(int k) {. if (stateCleft( !=,.EATING && stateLk ,;= JDINGRY F&, state[right(k)] != EATING) ' I stateCk1 = EATING;

,, '.:

3

where this refers to the object owning method. Threads can use wait and notify inside synchronized blocks.

, 'I ,

synchronized

3 public synchronized void takeForks(int state Cil = HUNGRY; test(i);

I

:.. object.wait(); ...

i> c

248

(object

> 1

object

.notify()

;

3 try C notificationCil.waitO; catch (InterruptedException

... 3 This idea is utilized to create notification objects for Java monitors that are close in behavior to named condition variables (remember each Java monitor has only a single nameless Fondition variable). Here is the dining philosophers server implemented with notification objects. Unfortunately, the coding is not as clean as if there were true named condition variables in Java,,a difficulty in teaching this technique to students. ‘The server creates a notification object for each philosopher. A hungry philosopher wishing to pick up its forks enters a synchronized block on its notification object, records its hungry state inside a synchronized block on ,the server (this), and then checks its fork availability. After leaving the synchronized block on this, the philosopher waits, if its forks are not available, inside its notification object for a signal. A philosopher relinquishing its forks checksboth neighbors to seeif either is waiting to eat. The philosopher sends a signal to a hungry neighbor if both of its for,ks are now available. ‘: class DiningServer

3 3 public void putForks(int i> ( . synchronized (this) { " state[i] = THINKING; test(left(i)); test(right(i)),; ' if (stateCleft( == EATING) synchronized (notificationCleft(i C notificationCleft(i)l.notify(); if (state[right(i)l == EATING) synchronized (n+ification[right(i)]) { notificationCright(i)].notifgO;

3

3 3 The instructor must clearly describe the pitfalls of signal-and-continue and barging in Java monitors and synchronized blocks. Synchronized blocks are lowerlevel, like the go to statement; monitors are higherlevel, like if, while, and for statements. The same trade-offs that apply in sequential programming also apply in the concurrent case. Notification objects can be very confusing to students if introduced soon after the monitor idea. Nested synchronized blocks and nested monitor invocations are subject to deadlock, which students need to understand. The JDK comeswith a collection of classesthat provide an interface to Berkeley sockets. These are used for network programming and are utilized in the message passing and rendezvous classeswritten by the author and described below. The JDK also includes a remote procedure call API, termed remote method invocation (R&II), that allows a thread in one JVM to invoke a method in an object in another JVM that is perhaps on a different computer. To send an object from one JVM to another as an argument of a remote method invocation, object serialization is used. Thii converts an object into a byte stream that is sent through a socket and converted into a copy of the object on the other end.

private int numF'hils = 0; private intC1 state = null; private ObjectC] notification = null; private static final int THINKING = 0, HUNGRY= 1, EATING = 2; public DiningServer(int numF'hils) { this.numPhils = numPhils; state = new int[numPhils]; for (int i = 0; i < numphils; i++) stateLi] = THINKING; notification = new Object@mF'hils]; for (int i = 0; i < numphils; i++) notification[il = new ObjectO; 3

private final iht right(int { return (i+l)%numPhils;

3

3

{

private final int left(int i) { return (numF'hils+i-i)'/,numPhils;

) e> {3

)

i) )

private void test(int k) C if (stateCleft( != EATING $8~ stateLk] == HUNGRYbt stateCright(k)l != EATING) stateLk = EATING; 3 -.

What Java Does Not Have The Sun Microsystems JDK for Windows 95 usesnative threads and so Java threads on this platform are time sliced with a quantum of about 50 milliseconds. But Solaris threads are not time sliced as of JDK 1.1.1; a thread retains the CPU until it suspends itself, yields, sleeps, waits for a lock or signal, joins another thread, or blocks on IO. Also, Solaris threads in the same JVM cannot yet take advantage of additional CPUs in a multiprocessor system.

public void tekeForks(int i) { synchronized (notification[i]) { synchronized (this) { state[i] = HUNGRY; test(i); if (stateCi1 == EATING) return;

249

socket is created-in each JVM (the two sockets are connected). The types of information passed in a message are

However, it is easy to introduce time slicing to Solaris threads. Ah object is instantiated that contains a high priority thread that repeatedly sleeps for 50 milliseconds. Each time its sleep ends, the currently executing thread is preempted. When the high priority thread goesback to sleep, another thread is allocated the:CPU, most likely a different’one than was preempted. Using time sliced threads, the instructor can write Java examples ofrace conditions, such as a thread being preempted in the middle of manipulating a linked list, resulting insa corrupted data structure. Java’ does not, have general counting semaphores or binary ones that’can be initialiied to zero. Binary and counting semaphore&sses are straightforward to write as Java monitors and can be made available to students in a class library by instructors of concurrent programming. Many semaphore-based programming assignments can then be given, such as an elevator simulation or a starvation-freeiversion of the dining philosophers. ) Students who have programmed in C++ are accustsmed to using the terminology “send a messageto an object” to mean invoking a method in that object. In Java, a threadinvoking.a method in another object temporarily leaves the object it is currently executing in and executes code in the other object. In concurrent programming; sending a messagehas a different meaning: a thread sends a messageobject to another thread executing in some other object and optionally blocks until the other thread receives the object sent. , Since Java does not have messagepassing, the author has implemented a variety of messagepassing styles in a class library for students to use in programming assignments. Each class implements a mailbox or channel that is shared by a collection of threads. Both synchronous (blocking sends),and asynchronous (non-blocking sends) are available (receives .always block). The oneway flow of information from sender.to receiver in synchronous messagepassing is sometimes called a simple rendezvous. .I I :I ! , ..‘*I-, ‘8 shared type:, class Message’ (. . . i”’ shared mailbox: SyncMessagePassing mailbox = new SyncMessagePassing(); one thread: ’ Message ms = n&i Messdge(. . . > ; send(mailboxl ms); ” I’ ‘another threadf Mesiage e;’ t I ‘ ,’ mr = (Message) redeive(mailbox); ’

l



l

l

l

object referencesfrom one thread to another, intra JVM; ’ data type values like int and double through a pipe, intra JVM; j data type values like int and double through connected sockets, inter JVM; serialized objects through a pipe, intra JVM;

l serialized objects through connected sockets, inter _ JVM.

Thus, distributed programming using a collection of workstations connected to,a local area network is done in Java with messagepassing mailboxes based on sockets. Students can write programs to solve large Nqueens problems in’ parallel,on a set of workstations or ‘ simulate the dining philosophers where each philosopher is executing on its own computer. In client-server programming, a client thread transacts with the server thread by sending a messagefollowed immediately by a receive that blocks until the server sends a reply messagecontaining the results of the transaction. mailbox shared by the client and server: AsyncMessagePassing mailbox = new AsyncMessagePassing(); client: send(mailbox, request) ; reply -= receive (mailbox) ; 8I server: request = receive(mailbox) ; compute reply; send(mailbox, reply); Another name for this is the extended rendezvous: two threads exchanging information synchronously. The author’s concurrent programming classlibrary contains an extended rendezvous class wrapped around a mailbox. shared by the client and server: ExtendedRendezvous er = new ExtendedRenhezvous(); client: reply = er. clientMakeRequestAwaitReply(request); server: request = er. serverGetRequest () ; compute reply; er.serverMakeReply(reply);

Within one JVM, threads share a single messagepassing object containing the mailbox; for messagepassing between JVMs, a messagepassing 0bject’containing.a 250

I’

If the client and server threads are in the sameJVM, one shared rendezvous object is used by the client to contact the server and the server to reply to the client. If the client and server are in different JVMs, perhaps ‘on different computers, two rendezvous objects are used, one by the client and one by the server, connected through sockets. In the former c&e, the client and server use object referencesto exchange information; in the latter case, the objects are serialized through sockets. These messagepassing and rendezvous classessupport a wide variety of client-server programming projects. The author believes these classes are easier for students to use in distributed computing applications than RMI. The author’s classessupport communication between threads in different JVMs, whereasBMI supports a thread executing a method in a,remote object.

PC961 Bill By&m and Tracy Camp, “After You,

Conclusions

Alfonse: A Mutual Exclusion Toolkit,,, ACM SIGCSE Bulletin, Vol. 28, No. 1, pp. 170174, March 1996.

‘.

The author has used Java during the past year to teach concurrelit programming to both undergraduates:and graduate students at Drexel University. These students have all previously programmed in C++ and therefore learn sequential Java quickly. Using instruct&supplied semaphore, message passing, and rendezvous classes, the students get substantial concurrent programming experience in a language they have all heard much about in the popular press. Their feedback has been uniformly b positive. However, there are a few caveats. Since Java monitors use signal-and-continue and have only one nameless condition variable, instrutitors will need to explam with pseudocode named condition variables and the sign& and-exit signaling discipline. Students need to code their Java monitors to handle barging. The dangers of using suspend and resume for thread condition synchronization also need emphasis. So, Alfonse [BC96], yes, your Java is ready par98].

Gary Cornell and Cay S. Horstmann, Core Java, Prentice-Hall, 1996.

[DeiSO]

Harvey M. Deitel, An l&roduction to Operating Systems, second edition, AddisonWesley, 1990.

Pa4

Stephen J. Hartley, Concurrent Programming: The Java Programming Language, Oxford University Press, 1998.

[SG94]

Abraham Silberschatz and Peter B. Gavin, Operating System Concepts, fourth edition, Addison-Wesley, 1994.

[Sta95]

William Stallings, Operating Systems, second edition, Prentice-Hall, 1995. 1 http:/Lwww.javasoft.com

[Sun97] [TW97;

References [And911 Gregory R. Andrews, Concurrent Programming: Principles and Practice, Benjamin/ Cummings, 1991. [AG96]

[CH96]

Ken Arnold and James Gosling, The Java Programming Language, Addison-Wesley, 0 1996.

/Ben901 M. Ben-Ari, Principles of Concurrent and Distributed Programming, PrenticeHall, 1, 1990.

PD931 Alan Burns and Geoff Davies, Concurrent Progrzunming, Addison-Wesley, 1993.

251

Andrew S. Tanenbaum and Albert S. ,Woodhull, Operating Systems: Design and Implementation, second edition, Prentice-Hall, 1997. ’