public class MVar {

    private Object content = null;
    private Object r = new Object();
    private Object w = new Object();
    private boolean empty = true;

    public MVar () {
    }

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

    public Object take () {
	synchronized (r) {
	    if (empty) {
		try {
		    r.wait();
		} catch (InterruptedException e) {}
	    };
	    empty = true;
	};
	synchronized (w) {
	    w.notify();
	}
	return content;
    }

    public void put (Object o) {
	synchronized (w) {
	    if (!empty) {
		try {
		    w.wait();
		} catch (InterruptedException e) {}
	    };
	    empty = false;
	    content = o;
	};
	synchronized (r) {
	    r.notify();
	}
    }

    public Object read () {
	synchronized (r) {
	    while (empty) {
		try {
		    r.wait();
		} catch (InterruptedException e) {}
	    };
	};
	synchronized (w) {
	    w.notify();
	}
	return content;
    }

    public Object swap (Object o) {
	synchronized (r) {
	    Object oldContent = take();
	    put(o);
	    return oldContent;
	}
    }

    public boolean isEmpty () {
	return empty;
    }

    public boolean tryPut (Object o) {
	synchronized (w) {
	    if (empty) {
		put(o);
		return true;
	    }
	    else {
		return false;
	    }
	}
    }

    public Object tryRead (Object o) {
	synchronized (r) {
	    if (empty) {
		return null;
	    }
	    else {
		return read();
	    }
	}
    }
}
