import java.io.*;

public class SyncConcurrentIncrement2 
{
	myInteger value = new myInteger(0);

	public SyncConcurrentIncrement2(int noThreads) throws Exception
	{
		Increment[] threadObjects = new Increment[noThreads];
		Thread[] threads = new Thread[noThreads];

		for (int i=0; i<noThreads; i++)
		{
			threadObjects[i] = new Increment(this);
		} //for
				
		DataOutputStream dos = new DataOutputStream( new FileOutputStream( "testfile") );
		dos.writeInt( 0 );
		
		for (int i=0; i<noThreads; i++)
		{
			threads[i] = new Thread( threadObjects[i] );
			threads[i].start();
		} //for
		
		for (int i=0; i<noThreads; i++)
		{
			threads[i].join();
		} //for
		
		DataInputStream dis = new DataInputStream( new FileInputStream( "testfile") );
		System.out.println("counter value: "+dis.readInt() );
	} //constructor
	
	public static void main(String argv[]) throws Exception
	{
		SyncConcurrentIncrement2 sci = new SyncConcurrentIncrement2(Integer.parseInt(argv[0])); 
	} //main()
	public void addOne()
	{
		try
		{
			DataInputStream dis;
			DataOutputStream dos;
			
			synchronized(value)
			{
				dis = new DataInputStream( new FileInputStream( "testfile" ) );
				value.setValue( dis.readInt() );
			
				System.out.println("thread named "+Thread.currentThread().getName()+" read: "+value.getValue());
				value.setValue( value.getValue()+1 );

				dos = new DataOutputStream( new FileOutputStream( "testfile" ) );
				dos.writeInt( value.getValue() );
				System.out.println("thread named "+Thread.currentThread().getName()+" wrote: "+value.getValue());
			} //synchronized
			
			dis.close();
			dos.close();
		} //try
		catch (IOException ioe)
		{
			System.out.println("An IOException occured\n"+ioe.getMessage());
			ioe.printStackTrace();
			System.exit(1);
		} //catch()
	} //addOne()		
} //class SyncConcurrentIncrement2
// --------------------------------------------------------
class Increment implements Runnable
{
	SyncConcurrentIncrement2 sci;
 
 	public Increment(SyncConcurrentIncrement2 sci)
 	{
 		this.sci = sci;
 	} //constructor
 
	public void run()
	{
		for (int i=0; i<10; i++)
		{
			sci.addOne();
		} //for
	} //run()
} //class Increment
// --------------------------------------------------------
class myInteger
{
	private int i;
	public myInteger(int i)
	{
		this.i = i;
	} //constructor()

	public void setValue(int i)
	{
		this.i = i;
	} //setValue()
	
	public int getValue()
	{
		return this.i;
	} //getValue()
} //class myInteger