George Blank University Lecturer

cavalcadejewelSoftware and s/w Development

Nov 18, 2013 (3 years and 6 months ago)

43 views

George Blank

University Lecturer

CS 602

Java and the Web

Object Oriented Software Development
Using Java

Chapter 11

Concurrent Programming


This is a chapter that does a good job of explaining
the technology. I want to add a little about the
reason for the technology.


The initial design purpose for Java was originally
aimed at embedded controllers. Quite often, new
technology tends to go in unforeseen directions.
For Java, it was the World Wide Web that changed
things.

Controller Multitasking


It is easy to understand the need for
concurrent programming in a controller. For
example, a washing machine will have to
monitor water levels and water temperature,
time a wash cycle, release detergent, accept
water and pump it out, control the agitator,
spin the tub, and several other tasks,
frequently more than one at a time.

Web Multitasking


But a Web Server is an even more demanding
environment. There may be hundreds (or, for
Google and Yahoo, thousands) of people
accessing a Web Site at the same time. The
need to serve all users efficiently demands
threads. Companies are very concerned with
efficiency. If a server is twice as fast, you only
need half as many.

Reactive Systems


One class of applications for multithreaded
systems is reactive systems that monitor a
series of inputs such as sensors and react
whenever an input indicates a change that
the system needs to respond to. The text
gives an autopilot for an airplane and a
patient monitoring system in a hospital as
examples of reactive systems.

Patient monitoring


I have often visited patients in a hospital when they were
hooked up to a patient monitoring system. The patient had a
number of sensors attached such as electrodes on the chest
to monitor cardiac functioning and a small cuff on their finger
to monitor pulse. Patients on respirators had monitors for
carbon dioxide and breathing rates. Whenever the value of an
input was abnormal, an alarm was triggered that would bring a
nurse to investigate it. This allowed fewer nurses to monitor
more patients effectively.

GUI Systems


Multithreading allows interactive systems
such as Windows to respond to user input
such as a mouse click even when the CPU is
busy with another task that might take a long
time to complete.

Multiprocessor Systems


Another key use for threads is in computers
with multiple CPUs. Each CPU can operate
on a different thread to efficiently perform
many operations at the same time. I have
used IBM and NCR computers that had from
8 to 16 CPU chips.

Process Overhead


One of the main time demands on a server is
starting up and shutting down processes.
With multithreading, one process can service
many users, and process overhead is
reduced dramatically. This greatly increases
throughput and reduces cost.

Cost Centers


Most companies treat information technology as
a cost center. In a cost center, a manager’s
primary concern is reducing costs (as opposed
to increasing sales or profits.) Therefore, most
companies are extremely interested in getting
the most value out of money spent on IT. Smart
employees should be very aware of this!

Active Object (Thread) Diagrams


Extending the Thread
class


Implementing the
Runnable interface

Thread

Runnable

MyThread

MyThread

run( )

run( )

Run Methods


In both the thread class and the runnable
interface, there is an abstract method,
run()
.
This is a
hook method

or
hot spot

for you to
add functionality to the thread. A hook
method is an object oriented device for
inheritance that uses an abstract method as a
placeholder for a later implementation.

Overriding the run method


The
run()

method in the thread class is a hook
method that must be overridden in a subclass.

public class MyThread extends thread {


public void run() {





}



}


To start a new thread, you create an instance of the
MyThread class and invoke the start method


new MyThread().start();

Example: extending Thread

The Runnable Interface


Sometimes you cannot extend thread
because you need to inherit functionality from
another class and Java does not permit
multiple inheritance.


In this case, you can implement the runnable
interface:

public class MyThread extends
AnotherClass implements runnable {


public void run() {


Example: implementing Runnable

java.lang.Thread methods


start(

)

A
New

thread enters the
Alive

state and
starts execution


sleep(

)

A
runnable

thread enters the
blocked

state for a timed period


join(

)

A
runnable

thread enters the
blocked

state and waits for another thread to finish


yield(

)

A
runnable

thread allows other
runnable

thread an opportunity to run at the same
time

java.lang.Thread methods (2)


interrupt(

)

A
runnable

thread sets the
interrupted flag. A
blocked

thread is awakened and
enters the
runnable
state, and an
InterruptedException

is thrown.


isAlive(

)

Returns
true

if the thread is in the
Alive

state


isInterrupted(

)

Returns
true

if the
Interrupted
flag is set

Thread Life Cycle (fig. 11.2)

Alive

Blocked

Runnable


Not

interrupted


interrupted

Wait to be

notified

Wait for target
to finish

Sleeping

Target Finish

wait( )

notify( ) |

notifyAll( )

join( )

yield()

sleep( )

Time Out

interrupt( )

interrupt( )

throws interruptedException

Dead

New

start( )

run( ) returns

Atomicity


An operation that cannot be divided is called
an
atomic
operation. It may be a simple
operation like assigning a value to an
attribute or a complex one like transferring
money from one account to another, where
you do not want to add the money to the
receiving account if you cannot deduct it from
the sending account.

Thread Safety


An important concern in concurrent systems is
preventing activities from interfering with each other.
With threads, this is called
thread safety
.


Usually, thread safety requires that only one activity
can use a process when it is in a state where an
atomic operation is not yet complete, and data may
be inconsistent. The Java solution is to provide a
synchronization

mechanism.

Critical Region


A program segment that should not be accessed or
interrupted is known as a
critical region
. An example
is an ATM transaction where the machine has to both
deduct the money from your account and give you
the cash. It cannot do either unless it can do both, so
the code is in a critical region from the time it begins
the transaction until it is complete and the data is
consistent.

Race Conditions


When two activities compete to use the same
resource, that state is known as a race
condition. If simultaneous access can lead to
inconsistency or other problems, then a
mechanism like synchronization or record
locking is required.

Synchronized Methods


The synchronized attribute is listed as a
method modifier to create a synchronized
method. The entire body of the method is the
critical region:

class MyClass {


synchronized void aMethod() {



<do something>


}

}

Synchronized Statements


You can also synchronize a statement in the
following form:



synchronized (
exp
) {



<do something>



}


In this case the expression
exp

must be of a
reference type.

Synchronization Locks


Synchronization is implemented by associating
objects with locks. A thread must have exclusive
possession of the appropriate
lock

to use the
resource.


For a synchronized instance method, the lock is
associated with the receiving object
this
.


For a synchronized statement, the lock associated
with the result of the expression
exp

is used.

How Java Locks Work


In Java, specialized code called a
monitor

provides
the locking mechanism, which blocks access to a
region of memory. If code is synchronized, after an
object reference is decoded to refer to that section of
memory, but before executing any code, it locks the
lock. After the code is executed, the lock is unlocked.
No other code may use the affected memory while it
is locked.

Shared locks


In the following code, it is possible for method
m1

to invoke
method
m2

as part of the same thread because they are in
the same class. To prevent conflicts and provide thread
safety,
m1

and
m2

share a common lock so that access to
one also locks the other.

public class A {


synchronized void m1 {


}


synchronized void m2 {


}



Textbook Bounded Queue


Examples 11.4 and 11.5 in the text show how
synchronization can be added with an extended
class.
class SyncBoundedQueue extends
BoundedQueue
to add synchronized access to the
isEmpty()
,

isFull()
,

getCount()
,

put(object)

and

get()
methods. Each of those
classes is synchronized and then simply calls the
method of the same name in the superclass.
(Example on next slide)

Example: Overriding put

public class SyncBoundedQueue extends
BoundedQueue {



public SyncBoundedQueue(int size) {



super(size);


}




synchronized public void put(object e) {



super.put(e);


}

Guards


The commands
wait()
,
notify()
, and
notifyAll()

of class
object

prevent thrashing of locks with unnecessary
locking and unlocking to see if an internal state has
changed. Instead the object suspends itself with
wait() until another thread wakes it with notify(). This
is particularly relevant when

threads cooperate
with each other in a producer
-
consumer
relationship such as example 11.5 in the text.

Text example


Before a method is executed, the guard is
tested. Execution can only proceed if the
guard is true.


In example 11.6 in the text, this prevents the
producer from trying to add to the queue
when it is full and it prevents the consumer
from trying to take an object from the queue
when it is empty.

Figure 11.3

Thread

SyncBoundedQueue

Consumer

Producer

put() method with guard

synchronized public void put(Object obj) { try {



while (isFull()) {





wait();



}


} catch (InterruptedException e) {


} super.put(obj);



notify();

}

get() method with Guard

synchronized public Object get() {


try {



while (isEmpty()) {




wait();



}


} catch (InterruptedException e) {


}


Object result = super.get();


notify();


return result;

}


Liveness Properties


Liveness refers to a desired set of
conditions when running code. Some of
them include:

1.
A task will eventually complete

2.
A thread will always respond to user input
until it is complete

3.
Certain status conditions must be displayed
and updated constantly

Contention


Contention

(a.k.a.
starvation

or
indefinite
postponement
) is a liveness failure that
occurs when a runnable thread never gets to
run.


To avoid contention, threads with higher
priorities must periodically invoke a
sleep()

or
yield()

method to give other cooperating
threads an opportunity to run.

Dormancy


Dormancy

is a liveness failure that occurs when a thread
that is blocked never becomes runnable. This typically
occurs when a thread that is blocked by
wait()

never
receives a
notify()

or
notifyAll()

command.


To prevent dormancy, make sure that any thread that can
be blocked by
wait()

will be reawakened by a
notify()

command. When in doubt, use the
notifyAll()
command.


Deadlock


Deadlock

is a liveness failure that occurs
when two or more threads block each other
and none can make progress.


Deadlock detection and prevention are
difficult and have been the subject of
extensive research. As a topic, it is beyond
the scope of this course.

Premature Termination


Premature Termination

is another liveness
failure that occurs when a thread is
terminated before it completes, resulting in
blocking the progress of other threads
(dormancy).


In Example 11.6 in the text, if either the
producer or the consumer fails the other
thread will be blocked indefinitely.

Summary


Concurrent or multithreaded programs can run
several threads at the same time.


A thread is a single sequential flow of control within a
program that requires fewer resources and has less
protection than a process.


Threads either extend the thread class or implement
the runnable interface.


The life cycle of a thread includes three states


new,
alive, or dead.

Summary (2)


A thread in the alive state can be either runnable or blocked
.


The JVM assigns an integer priority to each thread. This can
be modified for performance tuning.


Critical regions are segments of code that should only be
accessed by one thread at a time.


Race hazards could leave objects in an inconsistent state.


A guard is a precondition for the successful execution of an
action.

Summary (3)


Liveness refers to desirable conditions during the execution of
a program. Common examples of liveness failures include:


Contention (Starvation or Indefinite Postponement)


Dormancy


Deadlock


Premature Termination

Bibliography


Jia, Xiaoping, Object Oriented Software
Development Using Java
. Addison Wesley,
2003