Welcome!

Java Authors: Liz McMillan, Walter H. Pinson, III, Maureen O'Gara, Yakov Werde, Tony Bishop

Related Topics: Java

Java: Article

Designing Objects for Concurrency

Designing Objects for Concurrency

Java's support for concurrency is sufficient enough to achieve a wide range of desired results. While the primitives provided are very powerful, they can also be easily misused and may lead to unpredictable behavior. It is well known that in a multithreaded environment, due to the lack of mature tools available, the debugging process could easily modify the state of the program being debugged.

It is unreasonable to expect all Java programmers to be experts in concurrent programming. Deciding if and when to use the concurrency mechanism is a problem in itself, but once the decision is made, a new and fundamental question arises: How could I be sure, that the correctness of my program will not be adversely affected? It is obvious that adding synchronization constructs to a sequential design is a completely wrong approach. One possible solution is to build higher level synchronization abstractions (e.g. rendezvous classes). But, as the old saying goes, when you do not know how to drive well, it does not matter how powerful the car is. It might be even more dangerous!

The approach taken in this paper is based on the process of understanding Design Patterns using a new feature like inner class from Java 1.1 Some of the samples will implement basic patterns like Waiter Threads and Early Reply Threads others will only suggest ways of thinking. It might be worthwhile to take the time to express some of the solutions at the level of patterns. The correctness of the programs with multiple possible behaviors called non-determinate will not depend on how the threads are interleaved by the scheduler on different platforms. Rather, it will be an expression of the correct implementation of a well known pattern. The simplest way to avoid worries that one day on one machine your program will encounter a deadlock or a starvation state is to follow the form of a well-proven designed pattern in a multithreaded environment.

Introduction
In the old days of non-concurrency object-oriented programming, we dealt with two personages: the Client who wants an activity to be performed and the Server containing the code to perform the activity. The personages are still alive! The Client may say: "I need to perform this activity and you, Server, could help me. I give you the context and part of my well being (read object state) and please help me". The Server tries, while the Client waits, and finally responds, "I did it, my health is normal, and your well being was not affected". Everyone is happy: we as programmers and our objects. But, there is another possible scenario. The Server responds: "I encounter this exception, do not count on my results and be careful, your health will be affected". And the conversation goes on, but at least we could easily trace the relationships between our little creatures. For a better understanding, sometimes I use interaction diagrams [1]. For those of you who are not used to such diagrams, here is a little bit of terminology.

To express the dynamic interactions between objects, a symbolism is introduced which depicts situations in object relationships. In the form x.message(arg), which is the mechanism of Java invocation, the object bound to variable x is called the target object. When the server tries to use other services acting as a client, we call it the host. The nodes represent forms of existence of an object and the evolution of relationship is represented by links sometimes annotated with a message. The interaction diagram gives us an intuitive image of protocols at the level of the object relationship.

So far, the timing of the execution was not a factor in our considerations. The Client can wait as long as the Server needs to complete its job. But here is the problem: What if the Client wants to perform another activity during the period in which Server tries its best to satisfy the request? It is obvious we need another personage: Thread. So, what is a thread in our object world? It is an object that has the ability to perform in an asynchronous mode. What does it mean? The following are the easier roles of a thread.
1. When the Client wants to call the Server, the Thread says, "Use me and you will be free to do whatever you want". So the Client builds a little help object with its request and gives this object to Thread. In pattern terminology, we have a Waiter Thread.
2. When the Server receives a request from Client, the Thread says, "Here I am Server, I know how to do it, use me and you, Server, can take other requests from Client. This type of relationship is defined as an Early Reply Thread model.

Basics
There are few basic constructs in Java for concurrency mechanism: the class java.lang.Thread; the keywords: synchronized and volatile, the methods defined in java.lang.Object: wait, notify, notifyAll. On the other hand, they generate a wide range of coding practice and design strategies. We define a Runnable as an object which is the instance of a class implementing Runnable interface. Since Thread class implements Runnable interface, every instance of at least a Thread class will be a Runnable. The run method of Thread class is defined as:

public void run() { if (target != null) target.run(); }

where target is a Runnable reference in constructor form Thread(Runnable target). There is an interesting point that should be mentioned: Any object can access the methods of a Thread class finding out the thread it is running within using the Thread static method: Thread.currentThread(). Thus, any Runnable can use methods defined in the Thread class without itself having to be a thread. Why is this important? Because it helps us in the process of debugging in the old-fashioned style using print statement. There are methods in the Thread class that are very useful for identifying the threads like: getName() or toString() and so on. The run method of a Runnable could be written as:

public void run() {
Thread runningThread = Thread.currentThread();
System.out.println("Born of: " + runningThread.toString());
...
System.out.println("Death of: " + runningThread.getName());
}

Sometimes it is important to know where the born of a thread occurs invoking start method or if the thread dies from natural causes (run method exits) all at a level of a Runnable in constructs of the form: class WhateverClass extends WhateverSuperClass implements Runnable.

As you know, JDK 1.1 is extended. One of the most useful features is the concept of inner classes. It helps us to implement some patterns in a natural way. An inner class is a class defined as a member of another class. The inner class can use the members of enclosing class and is not usable outside its scope. Because the inner class needs to determine the enclosing instance, the compiler adds an extra private member to the inner class constructor (Listing 1). Some confusion can arise from the combination of lexical scoping and inheritance. For example, if we have:

class A { int x=1; }
class B extends A { int x=2;
//inner class
class C { int x = 3; int sum() { return x + B.this.x +
((A)B.this).x; } }
}

what is the result of new B().new C().sum()? [6]. Let us examine the terms of sum: B.this.x is the value x in enclosing class B and ((A)B.this).x is the value of x in A. Since the language prohibits an inner class from having the same name as any of its enclosing classes the current instance can be referred to by qualifying the keyword 'this' like in expression B.this.x. Java allows inherited names to hide the ones defined in enclosing scope, but prohibits them from being used without explicit qualification. We can subclass an inner class C like:

class D extends B.C { int x = 4; B b;
//ctr must have at least one arg.
//an enclosing instance of class C which is B
D(B b) {b.super(); this.b = b;}
int sum() { return x + super.x + b.x + ((A)b).x; }
}

How could a subclass D of an inner class C be built without knowing the enclosing instance of the inner class? The answer is that such a subclass cannot be built, unless the constructor of D has an argument of type reference to enclosing instance of inner C. The first statement of the constructor must be an explicit constructor invocation qualifying the keyword 'super'. The value 10 is the result of an invocation of type new D(new B()).sum(). The code snippet shows how we could access hidden instances with qualifying names. The right expression of the method sum in D would be: int sum() { return x + super.sum(); } Any current instance of an inner class, other than the instance of inner class itself, is called 'enclosing instance' of an inner class. By qualifying the keyword 'new' we can specify explicitly the enclosing instance:

class Outer {
class Inner { ... }
Inner innerObj = this.new Inner();
}

There are many aspects not mentioned here, like anonymous class and how the synchronization is applied in the context of inner classes, but one fundamental question must be answered: Why do we need the inner class in the first place? Have you thought about how the callback mechanism could be implemented in Java? The natural way would be to have a feature like inner class where a construct like 'method pointer' could be built as we soon see the implementation of some patterns.

Fundamentals
The most difficult part in the process of reusable software is to abstract forms of organization. If a pattern describes a design form, it means that by having a pattern we not only reuse components, but more importantly, the interactions between components at a higher level of flow of organization. As an example, I will define and implement a type of Waiter Thread pattern called Operation. What is the Waiter Thread Pattern? It is a model where the thread is constructed by a client and the server method could be executed asynchronous. It should be applied when waiting or blocking are not the right options for a client which wants to perform other activities. If we think of an Operation as applying an operator to an operand, we see how easy is to define a pattern of type Waiters. The unary operator of primitive type in Java[3] should be a model of an abstract unary operator which could be applied to a reference type. Let's try to design such an operator having its operand type as an abstract inner class (see Listing 2).

Defining an Operator in this form has some advantages. The Operator is closely related to its operand, it could inform the client (operation) at least about its success/failure and, more importantly, it is a Runnable.

How should an Operation pattern of client type look? For implementing the callback mechanism required by the server, it is clear that a runnable inner class should be defined and a start type method must be included for launching the operation. So a class Operation would look like Listing 3.

As an example, let us suppose that we define an operator called Show and an operand called URL (Listing 4). Applying the operator Show to operand URL gives us the operation ShowURL. The implementation of Operation pattern for this particular case is shown in Listing 5.

Why is ShowURL a type of Waiter Thread pattern? Because the client ShowURL builds a thread and calls the server to apply the operator Show to the operand URL. If we want to execute the operation ShowURL with String url = "http://www.javadevelopersjournal.com", the invocation is:

new ShowURL(url).start();

Thus, the invocation of the form

new OperatorOperand(arg).start()

is an operation with intricacies resembling the invocation of a unary operator ++ to operand j in expression ++j.

Conclusions
The next and natural question would be: Why do we need such an Operation pattern when there is a simple way, a direct approach? Because what we created can be applied to whatever operations you think of: Read/WriteFile, RenderImage, DrawForm and so on. The preferred method is a matter of choice, but in the world of reusable components it would be nice to have well-defined patterns which could be used or extended. I did not approach the synchronization technique that will be tackled in my next article. The pattern could be granularly refined at level of sending and receiving data. Thinking back to the inner classes, I remember my wise teacher G. Auslander, mentioning Einstein's words, "Many times I realize how much my own outer and inner life is built upon the efforts of my fellow men, and how earnestly I must exert myself in order to give in return as much as I have received". I hope this introduction helped.

References
1. Doug Lea "Concurrent Programming in Java Design Principles and Patterns" Addison-Wesley 1997.
2. E. Gamma, R. Helm, R. Johnson, J. Vlissides "Design Patterns" Addison-Wesley 1995.
3. K. Arnold, J. Gosling "The Java Programming Language" Addison-Wesley 1996.
4. Brian Maso, "Thread Synchronization in Java" Java Developer's Journal 1996.

More Stories By Jordan Anastasiade

20+ years experience as programmer.
Professor teaching Web Service - Seneca College @ York University


------ Publications ------
Java Developer's Journal

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.