package edu.nyu.cs9053.concurrency.chapter14;

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

/**
 * User: blangel
 * Date: 7/26/14
 * Time: 10:27 AM
 */
public class UnownedLockCondition {

    private final Lock lock = new ReentrantLock();

    private final Condition greaterThan99 = lock.newCondition();

    private Thread watcher;

    private Thread worker1;

    private int value;

    public void unownedLockCondition() {
        Runnable watch = new Runnable() {
            @Override public void run() {
                while (!interrupted()) {
                    lock.lock();
                    try {
                        while (value < 100) {
                            System.out.printf("Unnecessary CPU usage (value < 100, don't want to be running)%n");
                            greaterThan99.await();
                        }
                        watcher.interrupt();
                        worker1.interrupt();
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        break;
                    } finally {
                        lock.unlock();
                    }
                }
            }
        };
        Runnable watchWithoutLock = new Runnable() {
            @Override public void run() {
                while (!interrupted()) {
                    try {
                        while (value < 100) {
                            System.out.printf("Unnecessary CPU usage (value < 100, don't want to be running)%n");
                            greaterThan99.await();
                        }
                        watcher.interrupt();
                        worker1.interrupt();
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                }
            }
        };
        Runnable work = new Runnable() {
            @Override public void run() {
                while (!interrupted()) {
                    lock.lock();
                    try {
                        value += 1;
                        if (value >= 100) {
                            greaterThan99.signalAll();
                        }
                    } finally {
                        lock.unlock();
                    }
                }
            }
        };
        Runnable workConditionWithoutLock = new Runnable() {
            @Override public void run() {
                while (!interrupted()) {
                    lock.lock();
                    try {
                        value += 1;
                    } finally {
                        lock.unlock();
                    }
                    if (value >= 100) {
                        greaterThan99.signalAll();
                    }
                }
            }
        };
        watcher = new Thread(watch);
        worker1 = new Thread(workConditionWithoutLock);
        watcher.start();
        worker1.start();
    }

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

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