Difference between revisions of "CSC352 Synchronization and Java Threads"

From dftwiki3
Jump to: navigation, search
(Critical Section)
(Critical Section)
Line 113: Line 113:
 
: What should happen in Java when two threads attempt to modify a shared resource (variable or object).  Specifically, what should happen with the thread that is first to grab the resource, and what should happen with the slower thread?
 
: What should happen in Java when two threads attempt to modify a shared resource (variable or object).  Specifically, what should happen with the thread that is first to grab the resource, and what should happen with the slower thread?
 
<br />
 
<br />
 +
=The Concept of a '''Lock'''=
 +
* ''Intrinsic Lock'' = ''Monitor Lock'' =''Monitor'' (most common definition)
 +
* In Java each object contains a '''Lock'''
 +
* ''Exclusive access''' to the object can be performed by ''acquiring'' the lock.
 +
* A thread ''locking'' an object must ''release'' it when it's done updating it.
 +
* The keyword '''synchronized( )''' is used to
 +
** define an object whose lock is going to be used
 +
** define a section of code between { and } that is critical and should be executed in an atomic matter (but atomicity is not actually required any longer...  can you see why?)
 
<br />
 
<br />
 
<br />
 
<br />

Revision as of 14:34, 9 September 2013

--D. Thiebaut (talk) 14:10, 9 September 2013 (EDT)


This page treats of the concepts of synchronization of parallel programs in general, applied to the Java platform in particular.



References

A good source of information for the material presented here is

The programs covered in this page can be found in this page:


It all starts at the Lowest Level: Assembly Language (again)

Let's look at a different parallel computation of Pi. Imagine that the two threads in the ParallelPi program updated a global sum variable by doing something like this?

    sum += thread_sum;

where thread_sum is a local variable used by the thread function to accumulate the terms of the series. The actual program can be found here.

Question 1
Figure out the assembly language for the java statement above
Question 2
Assume that main memory is a stack of index cards. One index card is sum. Two people in the class represent two different processors. Their notebook represent their registers. Execute these instructions simultaneously and figure out if there's a way for their simultaneous operation to fail.
Question 3
What makes the code fail? What is the processor missing?
Question 4
What is a way around the problem, such that two parallel update of the variable sum will increment it by 2, every time?


Demo


The Badly Synchronized Parallel Program

/*
 * UnsynchronizedThreadExample.java
 * D. Thiebaut
 * Undocumented code that computes Pi with 2 threads, but is terribly
 * flawed in the way it updates the global sum...
 */
package DT;

public class UnsynchronizedThreadExample {

        static int sum = 0;
        
        class PiThreadBad extends Thread {
                private int N;                  // the total number of samples/iterations 

                public PiThreadBad( int Id, int N ) {
                        super( "Thread-"+Id ); // give a name to the thread
                        this.N          = N;
                }
                        
                @Override
                public void run() {
                        for ( int i=0; i<N; i++ )
                                sum ++;
                }
        }

        public void process( int N ) {
            long startTime = System.currentTimeMillis();
            PiThreadBad t1 = new PiThreadBad( 0, N );
            PiThreadBad t2 = new PiThreadBad( 1, N );
                
            //--- start two threads ---
            t1.start();
            t2.start();
                
            //--- wait till they finish ---
            try {
                t1.join();
                t2.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
                
            System.out.println( "sum = " + sum );
            System.out.println( "Execution time: " + (System.currentTimeMillis()-startTime) + " ms" );
        }
    
    public static void main(String[] args) {
        int N = 100000000;
        UnsynchronizedThreadExample U = new UnsynchronizedThreadExample();
        U.process( N );
    }

}


Output

java DT.UnsynchronizedThreadExample 
sum = 198846243
Execution time: 25 ms


Critical Section

A series of instructions that are executed in an atomic fashion.

Question
We have seen this before, but just to make sure we all remember this: how can we create a critical section in assembly?


More challenging question
What should happen in Java when two threads attempt to modify a shared resource (variable or object). Specifically, what should happen with the thread that is first to grab the resource, and what should happen with the slower thread?


The Concept of a Lock

  • Intrinsic Lock = Monitor Lock =Monitor (most common definition)
  • In Java each object contains a Lock
  • Exclusive access' to the object can be performed by acquiring the lock.
  • A thread locking an object must release it when it's done updating it.
  • The keyword synchronized( ) is used to
    • define an object whose lock is going to be used
    • define a section of code between { and } that is critical and should be executed in an atomic matter (but atomicity is not actually required any longer... can you see why?)