public class MVar<T> {

    private T content = null;

    private Object r = new Object(),
	           w = new Object();

    private boolean empty;

    public MVar () {
  	empty = true;
    }

    public MVar (T o) {
  	empty = false;
	content = o;
    }

    public T take () throws InterruptedException {
	synchronized (r) {
	    while (empty) {
		r.wait();
	    };
	    // Hier kommt maximal ein Thread hin!
	    synchronized (w) {
		empty = true;
		w.notify();
		return content;
	    }
	}
    }

    public T read () throws InterruptedException {
	synchronized (r) {
	    while (empty) {
		r.wait();
	    };
	    r.notify();
	    synchronized (w) {
		return content;
	    }
	}
    }

    public void put (T o) throws InterruptedException {
	synchronized (w) {
	    while (!empty) {
		w.wait();
	    };
	    // Hier kommt maximal ein Thread hin!
	    synchronized (r) {
		empty = false;
		content = o;
		r.notify();
	    }
	}
    }

    public boolean tryPut (T o) {
	synchronized (w) {
	    if (!empty) {return false;}
	    else {
		// Hier kommt maximal ein Thread hin!
		synchronized (r) {
		    empty = false;
		    content = o;
		    r.notify();
		    return true;}
	    }
	}
    }

    public T tryTake () {
	synchronized (r) {
	    if (empty) {return null;}
	    else {
		// Hier kommt maximal ein Thread hin!
		synchronized (w) {
		    empty = true;
		    w.notify();
		    return content;
		}
	    }
	}   
    }

    public void write (T o) {
	synchronized (w) {
	    synchronized (r) {
		if (empty) {r.notify();};
		empty = false;
		content = o;
	    }
	}
    }

    public T swap (T o) throws InterruptedException {
	synchronized (r) {
	    while (empty) {
		r.wait();
	    };
	    // Hier kommt maximal ein Thread hin!
	    synchronized (w) {
		T old = content;
		content = o;
		return old;
	    }
	}
    }

    public boolean isEmpty() {
	synchronized (r) {
	    synchronized (w) {return empty;}
	}
    }
}
