/**
 * Count the overlaps
 */
class CountRace extends Thread {
    private int count;
    private CountAccumulate acc;

    public CountRace( int count, CountAccumulate acc ) {
	this.count = count;
	this.acc = acc;
    }
    public void run() {
	for( int i = 0; i < count ; i++ ) {
	    acc.inc();
	}
    }
    public static void main( String[] args )  {
        if ( args.length != 1 ) {
            System.out.println("java CountRace loops");
            System.exit( 1 );
        }
        long t = System.currentTimeMillis();
        int loops = Integer.parseInt( args[0] );
	CountAccumulate acc = new CountAccumulate(loops);
	Thread t1 = new CountRace( 9000, acc );
	Thread t2 = new CountRace( 8000, acc );
	t1.start();
        Thread.yield();
	t2.start();
	try {
	    t1.join(); // wait for t1 to die
	    t2.join(); // wait for t2 to die
	}
	catch( InterruptedException ex ) {
	}
	System.out.println( acc.getCount() + " == " + 17000 );
	System.out.println( "overlaps = " + acc.getOverlap() );
        t = System.currentTimeMillis() - t;
        System.out.println( "elapsed = " + t );

    }
}

class CountAccumulate {
    private int sum;
    private int overlap;
    private int loops;
    Thread cur;

    public CountAccumulate( int loops ) {
	this.sum = 0;
        this.overlap = 0;
        this.cur = null;
        this.loops = loops;
    }

    public synchronized void startOverlap(){
        if ( cur != null ) {
            overlap++;
        }
        else {
            cur = Thread.currentThread();
        }
    }

    public synchronized void endOverlap(){
        Thread c = Thread.currentThread();
        if ( c == cur ) {
            cur = null;
        }
    }

    public void inc() {
        startOverlap();
	int s = sum;
	for( int i = 0 ; i < loops ; i++ ) 
	    ; // do nothing
	sum = s + 1;
        endOverlap();
    }

    public int getCount() {
	return sum;
    }

    public int getOverlap() {
        return overlap;
    }
}
