import java.io.*;

public class UsrLockConcurrentIncrement 
{
	boolean locked = false;
	
	public UsrLockConcurrentIncrement(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 boolean obtainLock()
	{
		if (locked)
		{
			System.out.println("thread named "+Thread.currentThread().getName()+" cannot obtain lock");
			return false;
		} //if
		else
		{
			System.out.println("thread named "+Thread.currentThread().getName()+" obtained lock");
			locked = true;
			return true;
		} //else	
	} //obtainLock()
	
	public void releaseLock()
	{
		System.out.println("thread named "+Thread.currentThread().getName()+" released lock");		
		locked = false;
	} //releaseLock()
	
	public static void main(String argv[]) throws Exception
	{
		UsrLockConcurrentIncrement ci = new UsrLockConcurrentIncrement(Integer.parseInt(argv[0])); 
	} //main()

	public void addOne()
	{
		try
		{
			while ( !this.obtainLock() )
			{
				System.out.println("thread named "+Thread.currentThread().getName()+" waiting for lock");
			} //while
				
				DataInputStream dis = new DataInputStream( new FileInputStream( "testfile") );
				int value = dis.readInt();
				
				System.out.println("thread named "+Thread.currentThread().getName()+" read: "+value);
				value++;
	
				DataOutputStream dos = new DataOutputStream( new FileOutputStream( "testfile") );
				dos.writeInt( value );
				System.out.println("thread named "+Thread.currentThread().getName()+" wrote: "+value);
				
				dis.close();
				dos.close();
			this.releaseLock();
		} //try
		catch (IOException ioe)
		{
			System.out.println("An IOException occured\n"+ioe.getMessage());
			ioe.printStackTrace();
			System.exit(1);
		} //catch()
	} //addOne()		
} //class UsrLockConcurrentIncrement
// --------------------------------------------------------
class Increment implements Runnable
{
	UsrLockConcurrentIncrement ci;
 
 	public Increment(UsrLockConcurrentIncrement ci)
 	{
 		this.ci = ci;
 	} //constructor
 
	public void run()
	{
		for (int i=0; i<10; i++)
		{
			ci.addOne();
		} //for
	} //run()
} //class Increment