Difference between revisions of "CSC352: Java Threads and Synchronization Examples"

From dftwiki3
Jump to: navigation, search
(A Synchronized Version of the Same Program)
(A second way of synchronizing the threaded computation of Pi)
Line 141: Line 141:
 
=A second way of synchronizing the threaded computation of Pi=
 
=A second way of synchronizing the threaded computation of Pi=
  
 +
<br />
 +
This time, instead of creating a synchronized method (by the way, the synchronized method should not be one of the thread's method, but a method outside the inherited thread class), we synchronize on an object global to the threads and the main program.  This object cannot be a simple type (such as '''int'''), but a real object (e.g. Integer).
 
<br />
 
<br />
 
<source lang="java">
 
<source lang="java">
Line 202: Line 204:
 
</source>
 
</source>
 
<br />
 
<br />
 +
 +
==Output==
 +
 +
sum = 200000000
 +
Execution time: 8620 ms
 +
 
 +
Similar behavior as the first version.  The synchronization code definitely add a serious overhead to the computation.  Sometimes it is a necessary solution for a problem.  In other cases, such as in the computation of Pi, we can find an approach that is safe but does not require synchronization.
 +
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
[[Category:CSC352]][[Category:Java]]

Revision as of 21:21, 4 September 2013

--D. Thiebaut (talk) 21:12, 4 September 2013 (EDT)


A Badly Written (and Flawed) Multithreaded Computation of Pi


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 ) {
		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 );
	}
	
	public static void main(String[] args) {
		int N = 100000000;
		UnsynchronizedThreadExample U = new UnsynchronizedThreadExample();
		U.process( N );
	}

}


Output

sum = 180612836
Execution time: 19 ms

Note that the sum should really be 200000000, as both threads increment sum 100000000 times. The result is certainly incorrect.

Note also that the execution time is quite fast: 19 ms.


A Synchronized Version of the Same Program

We decide to put the statement that increments the variable sum into a function, and ask Java to synchronize around the function, i.e. make sure than only one thread at a time runs through this function. In other word, the synchronized function becomes atomic for threads.


package DT;

public class SynchronizedThreadExample {

	int sum = 0;
	Integer lock=0;
	
	SynchronizedThreadExample() {
		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++ )
				synchronized( lock ) {
					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;
		SynchronizedThreadExample U = new SynchronizedThreadExample();
		U.process( N );
	}

}


Output

sum = 200000000
Execution time: 8448 ms

Note that the result is now correct. However the execution time is 400 longer!


A second way of synchronizing the threaded computation of Pi


This time, instead of creating a synchronized method (by the way, the synchronized method should not be one of the thread's method, but a method outside the inherited thread class), we synchronize on an object global to the threads and the main program. This object cannot be a simple type (such as int), but a real object (e.g. Integer).

package DT;

public class SynchronizedThreadExample2 {

	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++ )
				incrementSum();
		}
	}
	
	private synchronized void incrementSum() {
		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;
		SynchronizedThreadExample2 U = new SynchronizedThreadExample2();
		U.process( N );
	}

}


Output

sum = 200000000
Execution time: 8620 ms
 

Similar behavior as the first version. The synchronization code definitely add a serious overhead to the computation. Sometimes it is a necessary solution for a problem. In other cases, such as in the computation of Pi, we can find an approach that is safe but does not require synchronization.