public class SyncDL3 {
	private myInteger i1;
	private myInteger i2;
		
	private myComplex c1;
	private myComplex c2;
	
	public SyncDL3(int noThreads) {
		i1 = new myInteger(1);
		i2 = new myInteger(2);
			
		c1 = new myComplex( i1, i2, "c1" );
		c2 = new myComplex( i2, i1, "c2" );

		for (int i=0; i<noThreads; i++) {
			new Thread( new BlockingThread(c1,c2) ).start();
			new Thread( new BlockingThread(c2,c1) ).start();
		} //for
	} //constructor

	public static void main(String argv[]) {
		new SyncDL3(Integer.parseInt(argv[0]));
	} //main()
} //class SyncDL3

class BlockingThread implements Runnable {
	myComplex c1;
	myComplex c2;
	
	public BlockingThread(myComplex c1, myComplex c2) {
		this.c1 = c1;
		this.c2 = c2;
	} //constructor	
	
	public void run() {
		System.out.println("("+Thread.currentThread().getName()+") "+c1.toString() +" + "+ c2.toString() +" = "+ (c1.add(c2)).toString() );
	} //main()

} //class BlockingThread

class myComplex {
	private myInteger real;
	private myInteger imaginary;
	private String name;
	
	public myComplex (myInteger re, myInteger im, String name) {
		real = re;
		imaginary = im;
		this.name = name;
	} //constructor
	
	public synchronized myComplex add (myComplex c) {
		System.out.println(Thread.currentThread().getName()+" entered add of number "+name);
		myInteger resultRealPart = new myInteger( this.getRealPart()+c.getRealPart() );
		System.out.println(Thread.currentThread().getName()+" calculated real part of number "+name);
		myInteger resultImaginaryPart = new myInteger( this.getImaginaryPart()+c.getImaginaryPart() );
		System.out.println(Thread.currentThread().getName()+" left add of number "+name);
		return ( new myComplex(resultRealPart, resultImaginaryPart, "" ) );
	} //add()
	
	public synchronized int getRealPart() {
		System.out.println(Thread.currentThread().getName()+" entered getRealPart of number "+name);
		return real.get();
	} //getRealPart()
	
	public synchronized int getImaginaryPart() {
		System.out.println(Thread.currentThread().getName()+" entered getImaginaryPartof number "+name);
		return imaginary.get();
	} //getImaginaryPart()
	
	public synchronized String toString() {
		StringBuffer result = new StringBuffer( ""+real.get() );
		int img = imaginary.get();
		
		if (img >= 0)
			result.append("+i"+img);
		else
			result.append("i"+img);
		return ( result.toString() );
		} //printValue()
} //class myComplex 

class myInteger {
	private int value;
	
	myInteger (int init) {
		value = init;
	} //constructor
	
	public synchronized void set(int value) {
		this.value = value;
	} //set()
	
	public synchronized int get() {
		return value;
	} //get()
} //class myInteger
