I’m loosely following a tutorial on Java NIO to create my first multi-threading, networking Java application. The tutorial is basically about creating an echo-server and a client, but at the moment I’m just trying to get as far as a server receiving messages from the clients and logging them to the console. By searching the tutorial page for "EchoServer" you can see the class that I base most of the relevant code on.
My problem is (at least I think it is) that I can’t find a way to initialize the queue of messages to be processed so that it can be used as I want to.
The application is running on two threads: a server thread, which listens for connections and socket data, and a worker thread which processes data received by the server thread. When the server thread has received a message, it calls processData(byte[] data) on the worker, where the data is added to a queue:
1. public void processData(byte[] data) {
2. synchronized(queue) {
3. queue.add(new String(data));
4. queue.notify();
5. }
6. }
In the worker thread’s run() method, I have the following code:
7. while (true) {
8. String msg;
9.
10. synchronized (queue) {
11. while (queue.isEmpty()) {
12. try {
13. queue.wait();
14. } catch (InterruptedException e) { }
15. }
16. msg = queue.poll();
17. }
18.
19. System.out.println("Processed message: " + msg);
20. }
I have verified in the debugger that the worker thread gets to line 13, but doesn’t proceed to line 16, when the server starts. I take that as a sign of a successful wait. I have also verified that the server thread gets to line 4, and calls notify()on the queue. However, the worker thread doesn’t seem to wake up.
In the javadoc for wait(), it is stated that
The current thread must own this object’s monitor.
Given my inexperience with threads I am not exactly certain what that means, but I have tried instantiating the queue from the worker thread with no success.
Why does my thread not wake up? How do I wake it up correctly?
Update:
As @Fly suggested, I added some log calls to print out System.identityHashCode(queue) and sure enough the queues were different instances.
This is the entire Worker class:
public class Worker implements Runnable {
Queue<String> queue = new LinkedList<String>();
public void processData(byte[] data) { ... }
@Override
public void run() { ... }
}
The worker is instantiated in the main method and passed to the server as follows:
public static void main(String[] args)
{
Worker w = new Worker();
// Give names to threads for debugging purposes
new Thread(w,"WorkerThread").start();
new Thread(new Server(w), "ServerThread").start();
}
The server saves the Worker instance to a private field and calls processData() on that field. Why do I not get the same queue?
Update 2:
The entire code for the server and worker threads is now available here.
I’ve placed the code from both files in the same paste, so if you want to compile and run the code yourself, you’ll have to split them up again. Also, there’s abunch of calls to Log.d(), Log.i(), Log.w() and Log.e() – those are just simple logging routines that construct a log message with some extra information (timestamp and such) and outputs to System.out and System.err.
I’m going to guess that you are getting two different
queueobjects, because you are creating a whole newWorkerinstances. You didn’t post the code that starts theWorker, but assuming that it also instantiates and starts theServer, then the problem is on the line where you assignthis.worker = new Worker();instead of assigning it to theWorkerparameter.The thread for the Worker is probably using the
workerinstance passed to the Server constructor, so the Server needs to assign its own worker reference to that same Worker object.