package edu.nyu.cs9053.concurrency.chapter14;

import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * User: blangel
 * Date: 7/26/14
 * Time: 8:28 AM
 */
public class RaceConditionWithLock {

    private final Random random = new Random();

    private final Lock lock = new ReentrantLock();

    private long value;

    public void race() {
        Runnable work = new Runnable() {
            @Override public void run() {
                while (!interrupted()) {
                    long random = (Math.abs(RaceConditionWithLock.this.random.nextLong() % 10L));
                    long expected = (value + random);
                    lock.lock();
                    try {
                        value += random;
                        if (value != expected) {
                            System.out.printf("Found %d != %d%n", value, expected);
                            Thread.currentThread().interrupt();
                        }
                    } finally {
                        lock.unlock();
                    }
                }
            }
        };
        worker1 = new Thread(work);
        worker2 = new Thread(work);
        worker1.start();
        worker2.start();
    }

    public void waitForAll() throws InterruptedException {
        worker1.join();
        worker2.join();
    }

    private boolean interrupted() {
        return (worker1.isInterrupted() || worker2.isInterrupted());
    }
    Thread worker1;
    Thread worker2;

    public static void main(String[] args) throws InterruptedException {
        RaceConditionWithLock condition = new RaceConditionWithLock();
        condition.race();
        condition.waitForAll();
    }
}
