Peculiar behavior with multiple threads/ volatile variables/ conditionals/loops (Java) - java

Here's a snippet of a web server that I am currently building...
// ...
threadPool = Executors.newCachedThreadPool();
while (true)
if(this.isOn) {
try { // listen for incoming connection
this.clientSocket = serverSocket.accept();
} catch (IOException e) {
System.err.println("LOG: >> Accept failed! ");
System.exit(1);
}
// as soon as a connection is established send the socket
// with a handler/processor to the thread pool for execution
threadPool.execute(new ClientRequestProcessor(clientSocket));
}
//...
Please note that the isOn variable is a VOLATILE boolean.
If I turn the if into a while... this code works... but as it is it doesn't. May I ask why? From a logical point of view both should work, even if I test that flag in an if... am I missing something?!
[Later edit:] By not working I mean... a browser (e.g. firefox) cannot connect, actually it keeps trying but timesout eventually. Again, if I change that if(isOn) into a while(isOn) it works like a charm.
Any suggestions/ideas are more than welcome!!!
P.S. I need this combo "while(true) if/while(test flag) {...}" because the server can be started/stopped from a GUI... so the top level while(true) is kind of needed so I can recheck whether I am on (and thus listening for connections) or if I am off (and don't really care about incoming connections). Needles to say the event handlers of the GUI can modify the flag at anytime.

A better solution is to close the server socket when you want it to stop and start a new one in a new thread when you want it to start. This way you reject new connections and don't consume CPU when its not doing anything.
When isOn == true and you turn it false, it will only not accept connections after the next new connection. (Could be any time later) Additionally any client new connections will just wait for the accept to be called (or eventually timeout) You can have up to 50 connections waiting to be accepted by default.
When isOn == false, your thread will busy wait, consuming a CPU. I suggest you put in a little delay such as Thread.sleep(250). This will cut CPU dramatically, but not delay starting again too much.
BTW:
if you get an exception, you should log/print it out. Otherwise when it fails you won't know why.
If accept fails, it could be the process is out of files, so you doesn't want it to just die, killing all existing connections.

If you have the while(true) and then if(this.isOn) the while loop has no way of stopping. What happens when the isOn flag is turned to false. The while loop never stops because it is essentially made to be infinite. Plug in an else statement to make it break and it should work as expected.
If you take out the if statement and just make it while(this.isOn) then when the isOn flag is turned to false the loop ends. No infinite loop.
Those are my thoughts at first glance ...

My assumption would be based on your tight loop there. Is it possible you have multiple instances of the program running on your server? The if(isOn) version will not shut down if you set isOn to false, instead it will simply loop forever burning your CPU.

Related

Passing a Java socket from thread A to B

In a server, there is a thread A listening for incoming connections, typically looping forever. When a connection is accepted, thread A creates a task (say, class Callable in Java) and submits it to an Executor.
All this really means is that A lost the reference to the socket, and that now there’s a thread B (created by the Executor) that manages the socket. If B experiences any exception, it would close the socket, and there is no risk that the socket, as an operating system resource, will not be reclaimed.
This is all fine if thread B starts. But what if the executor was shut down before B had a chance to get scheduled?
Does anyone think this is an issue? If the reference to the socket is lost due to this, would the garbage collector close the socket?
Yes, it sounds like an issue.
The OS will probably eventually free up the socket (at least if it's TCP, as far as I can tell) but it will probably take a relatively long time.
I don't think the garbage collector plays a role in this case. At least not for threads, which after having been started will usually keep running even if there is no reference to them in the code (this is true at least for non-daemon threads). Sockets may behave in a similar manner.
If you cannot guarantee the connection is going to be processed (by starting the handling Thread instance as soon as it is established) then you should keep a reference to the socket and make sure you close all of them as soon as possible, which probably means right after Executor.shutdown() or similar method has been called.
Please note that depending on how you ask the Executor to shut down it will either process or not threads which already have been submitted to execution but haven't yet started. So be sure to make your code behave accordingly.
Also if you have limited resources (available threads) to process incoming socket connections and don't want them to grow too much, consider closing them immediately after having been accepted so they don't pile up in the unprocessed wait queue, if this is feasible in your project. The client can then retry connecting at a later time. If you still need to consume connections as soon as they come in, consider a non-blocking I/O approach, which will tend to scale better (and up to a point).
If the reference to the socket is lost due to this, would the garbage collector close the socket?
Probably. But the garbage collector may not run until literally the end of next week: You can't rely on the GC running, pretty much ever, just because 'hey, java has a garbage collector'. It does, and it won't kick in until needed. It may simply never be needed.
Depending on the GC to close resources is a fine way to get your VM killed by the OS for using up too many system resources.
The real question is: What is the causal process that results in shutting down the executor?
If there is some sort of 'cancel all open connections' button, and you implemented that as a one-liner: queue.shutdown(), then, no - that is not a good idea: You'll now be leaning on the GC to clean up those sockets which is bad.
I assume your callables look like:
Socket socket = ....; // obtained from queue
Callable<Void> socketHandler = () -> {
try {
// all actual handling code is here.
} finally {
socket.close();
}
return null;
};
then yeah that is a problem: If the callable is never even started, that finally block won't run. (If you don't have finally you have an even bigger problem - that socket won't get cleaned up if an exception occurs during the handling of it!).
One way out is to have a list of sockets, abstract away the queue itself, and have that abstraction have a shutdown method which both shuts down the queue and closes every socket, guarding every step (both the queue shutdown as well as all the socket.close commands) with a try/catch block to ensure that a single exception in one of these steps won't just stop the shutdown process on the spot.
Note that a bunch of handlers are likely to still be chugging away, so closing the socket 'out from under them' like this will cause exceptions in the handlers. If you don't want that, shut down the queue, then await termination (guarded with try/catch stuff), and then close all the sockets.
You can close a closed socket, that is a noop, no need to check first and no need to worry about the impact of closing a ton of already-closed sockets.
But do worry about keeping an obj ref to an infinitely growing list of sockets. Once a socket is completely done with, get rid of it - also from this curated list of 'stuff you need to close if the queue is terminated'.
Of course, if the only process that leads to early queue termination is because you want to shut down the VM, don't worry about it. The sockets go away with the VM. In fact, no need to shutdown the queue. If you intend to end the VM, just.. end it. immediately: System.shutdown(0) is what you want. There is no such thing as 'but.. I should ask all the things to shut down nicely!'. That IS how you ask. Systems that need to clean up resources are mostly badly designed (design them so that they don't need cleanup on VM shutdown. All the resources work that way, for example), and if you must, register a shutdown hook.

Thread.sleep() taking longer than expected?

We have a Java client/server RMI application that uses a Persistence Framework. Upon starting a client session we start the following thread:
Thread checkInThread = new Thread() {
public void run() {
while(true) {
try {
getServer().checkIn(userId);
}
catch(Exception ex) {
JOptionPane.showMessageDialog(parentFrame, "The connection to the server was lost.");
ex.printStackTrace();
}
try {
Thread.sleep(15000);
}
catch(InterruptedException e) {
}
}
}
};
This is used to keep track of whether a client session loses connection to the server. If the client does not check in for 45 seconds, then there are a number of things we need to clean up from that client's session. Upon their next check in after they've gone beyond the 45 seconds threshold we boot them from the system which then allows them to log back in. In theory the only time this should happen is if the client PC loses connectivity to the server.
However, we have come across scenarios where the thread runs just fine and checks in every 15 seconds and then for an unknown reason, the thread will just go out to lunch for 45+ seconds. Eventually the client will check back in, but it seems like something is blocking the execution of the thread during that time. We have experienced this using both Swing and JavaFX on the client side. The client/server are only compatible with Windows OS.
Is there an easy way to figure out what is causing this to happen, or a better approach to take to make sure the check ins occur regularly at 15 second intervals assuming their is connectivity between client and server?
getServer().checkIn(userId);
getServer or checkIn functions may take more than 15 seconds to return, then for that reason
the thread will just go out to lunch for 45+ seconds.
This can happen when the client machine goes into sleep or hibernate mode. Usually when it's a laptop that just had its cover closed.
There can also be temporary network outages that last for >15 seconds, but allow connections to resume automatically when the network comes back. In this case, the client can be stuck in .checkIn(), not sleep()
You should absolutely and positively not do this. There is no such thing as a connection in RMI, ergo you are testing for a condtion that does not exist. You are also interfering with RMI's connection pooling. The correct way to accomplish what you're attempting is via the remote session pattern and the Unreferenced interface. RMI can already tell you when a client loses connectivity, without all this overhead. 'Still connected' has no meaning in RMI'.

program freezes when listening for client through sockets

I'm trying to make a server socket to listen to a client input stream but when i execute the start_listening() method, my program gets stuck. I even tried to remove the loop, but i still have the same problem. i guess that it waits for the client interaction. is there an alternative way to listen while the program is also working?
public static void start_listening(){
listener = new ServerSocket(9090);
while (true) {
Socket socket = listener.accept();
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
us = (User) in.readObject();
}
}
When using the sockets technique, accept() blocks the execution of the current thread until a client connects to the listening socket. This is a defined behavior. Java documentation says: "The method [accept()] blocks until a connection is made." Have the server run within a endless loop can be ok.
So, to get this whole thing run you might want to take a look at this socket example which uses threads. Inside the run() method of ConnectionHandler you would deal with your User object.
Besides that the loop never ends (I suppose you will break at some point), you should do that kind of stuff in a separate Thread or an AsyncTask, doing accept in the main thread makes Andriod freeze until somebody connects to the socket. That's why your program gets stuck.
You might just use a Boolean flag to indicate when to end the while loop.Other wise the loop keep iteration as it never breaks.
while (true) { //will it ever breaks ??
}

How Do You Stop A Thread Blocking for Network I/O?

I am currently trying to write a very simple chat application to introduce myself to java socket programming and multithreading. It consists of 2 modules, a psuedo-server and a psuedo-client, however my design has lead me to believe that I'm trying to implement an impossible concept.
The Server
The server waits on localhost port 4000 for a connection, and when it receives one, it starts 2 threads, a listener thread and a speaker thread. The speaker thread constantly waits for user input to the console, and sends it to the client when it receives said input. The listener thread blocks to the ObjectInputStream of the socket for any messages sent by the client, and then prints the message to the console.
The Client
The client connects the user to the server on port 4000, and then starts 2 threads, a listener and s speaker. These threads have the same functionality as the server's threads, but, for obvious reasons, handle input/output in the opposite way.
The First Problem
The problem I am running into is that in order to end the chat, a user must type "Bye". Now, since my threads have been looped to block for input:
while(connected()){
//block for input
//do something with this input
//determine if the connection still exists (was the message "Bye"?)
}
Then it becomes a really interesting scenario when trying to exit the application. If the client types "Bye", then it returns the sending thread and the thread that listened for the "Bye" on the server also returns. This leaves us with the problem that the client-side listener and the server-side speaker do not know that "Bye" has been typed, and thus continue execution.
I resolved this issue by creating a class Synchronizer that holds a boolean variable that both threads access in a synchronized manner:
public class Synchronizer {
boolean chatting;
public Synchronizer(){
chatting = true;
onChatStatusChanged();
}
synchronized void stopChatting(){
chatting = false;
onChatStatusChanged();
}
synchronized boolean chatting(){
return chatting;
}
public void onChatStatusChanged(){
System.out.println("Chat status changed!: " + chatting);
}
}
I then passed the same instance of this class into the thread as it was created. There was still one issue though.
The Second Problem
This is where I deduced that what I am trying to do is impossible using the methods I am currently employing. Given that one user has to type "Bye" to exit the chat, the other 2 threads that aren't being utilized still go on to pass the check for a connection and begin blocking for I/O. While they are blocking, the original 2 threads realize that the connection has been terminated, but even though they change the boolean value, the other 2 threads have already passed the check, and are already blocking for I/O.
This means that even though you will terminate the thread on the next iteration of the loop, you will still be trying to receive input from the other threads that have been properly terminated. This lead me to my final conclusion and question.
My Question
Is it possible to asynchronously receive and send data in the manner which I am trying to do? (2 threads per client/server that both block for I/O) Or must I send a heartbeat every few milliseconds back and forth between the server and client that requests for any new data and use this heartbeat to determine a disconnect?
The problem seems to reside in the fact that my threads are blocking for I/O before they realize that the partner thread has disconnected. This leads to the main issue, how would you then asynchronously stop a thread blocking for I/O?
I feel as though this is something that should be able to be done as the behavior is seen throughout social media.
Any clarification or advice would be greatly appreciated!
I don't know Java, but if it has threads, the ability to invoke functions on threads, and the ability to kill threads, then even if it doesn't have tasks, you can add tasks, which is all you need to start building your own ASync interface.
For that matter, if you can kill threads, then the exiting threads could just kill the other threads.
Also, a "Bye" (or some other code) should be sent in any case where the window is closing and the connection is open - If Java has Events, and the window you're using has a Close event, then that's the place to put it.
Alternately, you could test for a valid/open window, and send the "Bye" if the window is invalid/closed. Think of that like a poor mans' event handler.
Also, make sure you know how to (and have permission to) manually add exceptions to your networks' firewall(s).
Also, always test it over a live network. Just because it works in a loopback, doesn't mean it'll work over the network. Although you probably already know that.
Just to clarify for anyone who might stumble upon this post in the future, I ended up solving this problem by tweaking the syntax of my threads a bit. First of all, I had to remove my old threads, and replace them with AsyncSender and AsyncReader, respectively. These threads constantly send and receive regardless of user input. When there is no user input, it simply sends/receives a blank string and only prints it to the console if it is anything but a blank string.
The Workaround
try{
if((obj = in.readObject()) != null){
if(obj instanceof String)
output = (String) obj;
if(output.equalsIgnoreCase("Bye"))
s.stop();
}
}
catch(ClassNotFoundException e){
e.printStackTrace();
}
catch(IOException e){
e.printStackTrace();
}
In this iteration of the receiver thread, it does not block for input, but rather tests if the object read was null (no object was in the stream). The same is done in the sender thread.
This successfully bypasses the problem of having to stop a thread that is blocking for I/O.
Note that there are still other ways to work around this issue, such as using the InterruptableChannel.

Is setting a timeout on ObjectInputStream.readObject() safe?

I have an ObjectInputStream connected to an ObjectOutputStream through a socket, and I've been using Socket.setSoTimeout() to make ObjectInputStream.readObject() only block for 100ms. Since I started doing this I've been getting alot of StreamCorruptedError's while calling readObject(). Could the timeout be to blame?
I have a thread constantly getting new data through this function but I want to be able to stop it by setting a boolean to false. The thread has to keep polling the boolean and can't if it's blocked by readObject()
You can use Thread.interrupt to let it throw an InterruptedException, or in this case an InterruptedIOException. Make sure you don't swallow exceptions!
If you set the timeout shorter than the normal delays which might occur in reading a stream, you can expect the timeout to be in effect when the stream is still properly active.
100 ms seems like a long time, but not if there's disk or network traffic involved. Try timing out on something ridiculous, like a second.

Categories