I currently have a rather simple SSL server/client project that involves a standard Java backend and an Android frontend. I wanted to try to read a response from the server after I send data with the client. However, I encountered a little problem. The server doesn't always respond, so I had to somehow try to get a response in an asynchronous way. (because the read() method is a blocking one) After some messing around I found a working solution, but it seems so weird to me, like Im doing something that is potentially "dangerous". The first thing I did was to create a new Runnable and Thread object:
// "reader" is of type "BufferedReader"
Runnable receiveResponse = new Runnable() {
boolean stop = false;
@Override
public void run() {
try {
new Timer().schedule(new TimerTask() {
@Override
public void run() {
stop = true;
}
}, 5000);
char receive;
StringBuilder responseBuilder = new StringBuilder();
while (!stop && ((receive = (char) reader.read()) != END_OF_STREAM_CHAR)) {
responseBuilder.append(receive);
}
// If the server responds in time I can continue processing the response etc.
} catch (Exception ex) {
// Handle exception ...
}
}
};
Thread thread = new Thread(receiveResponse);
thread.start();
As you can see I used a boolean "stop" (that I set to true after 5 seconds) inside the while loop as an additional condition. The "reader.read()" method is a blocking one, so if I wouldn't implement some type of stopping the thread this method would block an infinite amount of time, if the server doesn't respond. Thats why I tried using a Timer that simply sets the "stop" boolean to true.
I know this isn't the best solution and at some point I would redesign this entire thing altogether, but I still wonder whether or not the thing I'm doing right now is okay or not. It certainly works, but that sadly doesn't mean anything.
You are right, such approach with starting one more thread is not perfect. It would be hard to support such code.
I'd suggest to use a Thread Executor instead. Your code could look as follows:
Runnable receiveResponse = new Runnable() {
...
};
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> future = executor.submit(receiveResponse);
try {
Object result = future.get(5000, TimeUnit.MILLISECONDS);
System.out.println("Completed successfully");
} catch (InterruptedException e) {
...
} catch (ExecutionException e) {
...
} catch (TimeoutException e) {
System.out.println("Timed out. Cancelling the runnable...");
future.cancel(true);
}
executor.shutdown();