/* message exchange device between threads. requires jdk 1.5+ In ada we saw the ability of two threads to synchronize using the entry - accept mechanism. Messages can also be exchanged at such synchronization points in the form of in/out parameters. In Java there is no such built-in mechanism, so we must construct one ourselfs. A message box contains a pointer to a message object named message. The exact type of M is to be determined by Java's new parametric typing technique (it can be any referenced type). Each concrete (as opposed to abstract) message box must implement a "synchcode" procedure. The body of this procedure cooresponds to the code inside an accept - do block in Ada. That is, it contains code that should be executed at the point of synchronization. A pair of client/server threads can synchronize and communicate through a message box. The client will call the "invoke" method, and pass it a pointer to a message. The server calls accept(this), which then dispatches to the concrete "synchcode" procedure. "synchcode" will then manipulate the message object through the pointer, carrying out whatever needs to happen at the synchronization point. accept and synchcode take a pointer parameter to a generic server Object, which means it can be an instance of any thread class. We must use Java's native synchronization mechanisms to implement the fact that the client and server threads may need to wait for eachother. That is, the client calling invoke must wait until the server has called accept and have finish executing synchcode. The server that calls accpet must also wait until the client calls invoke and have sent it a pointer to the message object to be exchanged. */ abstract class messagebox { public M message; // the message to be exchanged, must be reference type. public boolean synch = true; // synchronized or asynchronized exchange? public boolean ready = false; // is message ready for exchange? public abstract void synchcode(Object srv); // implemented by subclass public synchronized void invoke(M m) throws Exception { message = m; // sends message ready = true; notify(); // notifies accepting thread System.out.println("client has signaled server, now waiting..."); System.out.flush(); // forces immediate printing if (synch) wait(); // wait til synchcode has been executed } public synchronized void accept(Object srv) throws Exception { if (!ready) wait(); // wait for message to arrive synchcode(srv); // dispatch to synchronization code ready = false; notify(); // notifies invoking thread } } //messagebox // sample message type class pair { public int x, y; public pair(int a, int b) {x=a; y=b;} } // sample swap class defines what to do at synchronization point class swapper extends messagebox { public void synchcode(Object srv) { System.out.println("now at synchronization point"); int temp = message.x; message.x = message.y; message.y = temp; ((server)srv).z = message.x; // copy message value to server object try {Thread.sleep(4000);} catch(Exception e) {} // fake delay } } // info /////////////// thread classes: class client implements Runnable { swapper S; public client(swapper x) {S=x;} public void run() { try { pair p = new pair(2,3); Thread.sleep(3000); // comment out for different effect S.invoke(p); System.out.println("client after synch: "+p.x+" and "+p.y); } catch (Exception ee) {System.out.println(ee);} } // run } // client class server implements Runnable { swapper Sw; int z = 0; public server(swapper x) {Sw=x;} public void run() { try { Thread.sleep(1000); System.out.println("server waiting for client"); Sw.accept(this); System.out.println("server's z value is now "+z); } catch (Exception ee) {System.out.println(ee);} } // run } // client public class messages { public static void main(String[] args) throws Exception { swapper box = new swapper(); Thread t1 = new Thread(new client(box)); Thread t2 = new Thread(new server(box)); t1.start(); t2.start(); t1.join(); t2.join(); } // main }