ImageThread it = new ImageThread(this.imageURL,this);
Thread t = new Thread(it);
t.start();
I'm new to threads and had to implement the above in my field that loads an image, because it slowed down the UI thread.
Whether my threads are downloading an image or some json content, they appear to still be downloading even though the user has pushed a new mainscreen onto the uiapplication. This continuous loading could be a problem if a user enters a screen and then accesses another in quick succession. As a result, the last screen they are on only finishes its thread when the others are done.
What am I supposed to do with my threads that would be deemed responsible? I don't want my app to be bogged down by a queue of threads. How do I, say, cancel downloads on screen change?
I'm posting this question in Java since I think the process is the same.
You can force your threads to close by keeping a public close() method inside your class that extends Thread:
private class MyConnectionThread extends Thread {
/** determines whether the thread is runnuing or not. */
private boolean alive = false;
private HttpConnection hconn = null; // or whatever connection method you want to use ( SocketConnection etc.)
private InputStream inputStream = null; // or DataInputStream etc...
public MyConnectionThread() {
alive = false;
// ...
// ...
}
public void run() {
alive = true;
try {
String connection_parameter = ";deviceside=false"; // [For BlackBerry: ] this parameter is for connection using MDS, need to add different parameters for different connection methods.
hconn = (HttpConnection) Connector.open("http://your_url.com"+connection_parameter);
int response = hconn.getResponseCode();
if (response == HttpConnection.HTTP_OK) {
inputStream = hconn.openInputStream();
// process the result here by reading the inputStream ...
// ...
// ...
}
inputStream.close();
hconn.close();
}catch(Exception excp) {
// Handle Exceptions here...
}catch (Throwable e) {
// Exception in reading inputStream
}finally{
alive = false;
this.interrupt();
}
}
/**
* Forces the connection to close anytime.
*/
public void closeConnection() {
alive = false;
try {
if (inputStream != null) {
inputStream.close();
}
inputStream = null;
if (hconn != null) {
hconn.close();
}
hconn = null;
this.interrupt();
} catch (Exception excp) {
// Handle Exception here...
System.out.println("Exception in closing HttpConnection: " + excp.toString());
}
}
}
Now whenever you navigate to another screen you just need to call the MyConnectionThread.closeConnection() method to force-close this Thread.
See Also:
how-to-abort-a-thread-in-a-fast-and-clean-way-in-java
How can we kill the running thread in java?
How to Stop a Thread or a Task
Hope these will be helpful for you.
As #Rupak suggested you make method (using isDisplayed() for example):
boolean isScreenOnTop()
And pass it to the Thread (better over interface StopCondition.shouldStop()). And modify you downloading algorithm to next:
while(moreDataAvailable() && !topCondition.shouldStop()) {
loadNextDataChunk();
}
if (!topCondition.shouldStop()) {
notifyDataDownloaded();
}
Related
I have a small bit of code that runs in an applet that contains SWING controls and is used to write information to a socket on a certain port and then listens for a response. This works fine, but there is a problem with it. The port listener is essentially in a loop until null is received by the server. I want users to be able to perform other actions in the GUI instantiated by the applet while waiting for the server to respond (this could take minutes to occur). I also need to worry about the connection between the server and the client disconnecting. But the way the code is written, the applet appears to freeze (its really in a loop) until the server responds. How can I allow the listener to do its listening in the background, allowing other things to occur in the program. I assume I need to use threads and I'm sure for this application, it is easy to implement, but my lack of a solid thread foundation is hampering me. Below is the code (you can see how simple it is). How can I improve it to make it do what I need it to do>
public String writePacket(String packet) {
/* This method writes the packet to the port - established earlier */
System.out.println("writing out this packet->"+packet+"<-");
out.println(packet);
String thePacket = readPacket(); //where the port listener is invoked.
return thePacket;
}
private String readPacket() {
String thePacket ="";
String fromServer="";
//Below is the loop that freezes everything.
try {
while ((fromServer = in.readLine()) != null) {
if (thePacket.equals("")) thePacket = fromServer;
else
thePacket = thePacket+newLine+fromServer;
}
return thePacket; //when this happens, all listening should stop.
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
Thanks,
Elliott
There lots of different means of getting the IO performed on a different thread, but in this case you probably want to use SwingWorker.
Your code would look something like:
private final Executor executor = Executors.newSingleThreadExecutor();
public void writePacket(final String packet)
{
// schedules execution on the single thread of the executor (so only one background operation can happen at once)
//
executor.execute(new SwingWorker<String, Void>()
{
#Override
protected String doInBackground() throws Exception
{
// called on a background thread
/* This method writes the packet to the port - established earlier */
System.out.println("writing out this packet->"+packet+"<-");
System.out.println(packet);
String thePacket = readPacket(); //where the port listener is invoked.
return thePacket;
}
#Override
protected void done()
{
// called on the Swing event dispatch thread
try
{
final String thePacket = get();
// update GUI with 'thePacket'
}
catch (final InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (final ExecutionException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
private String readPacket()
{
String thePacket ="";
String fromServer="";
//Below is the loop that freezes everything.
try
{
while ((fromServer = in.readLine()) != null)
{
if (thePacket.equals(""))
thePacket = fromServer;
else
thePacket = thePacket+newLine+fromServer;
}
return thePacket; //when this happens, all listening should stop.
}
catch (IOException e)
{
e.printStackTrace();
return null;
}
}
All the network I/O should be in a separate thread.
BTW readLine() returns null when the server closes the connection, not when it has finished sending data for the moment.
This method functions as intended, in that it only gets one object at a time from the server at a time, handles that object, and then gets another. However, it seems that I need to, seemingly, turn it inside out, probably with Producer-Consumer:
public void inputOutput() throws IOException, ClassNotFoundException {
Socket socket = new Socket(server, portNumber);
boolean eof = false;
Title title = null;
State state = State.undefined;
try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream())) {
do {
try {
title = (Title) objectInputStream.readObject();
log.info(title.toString());
do {
state = State.undefined;
try {
c.printf("enter the state for record:");
state = State.valueOf(c.readLine());
} catch (java.lang.IllegalArgumentException iae) {
log.warning(Arrays.deepToString(State.values()));
}
} while (state == State.undefined);
title.setState(state);
title.setTitle("modified from client");
objectOutputStream.writeObject(title);
} catch (java.io.EOFException eofe) {
eof = true;
}
} while (!eof);
}
}
The "flow", of handling one object, and then sending it back, and then requesting another, is exactly what I want to replicate:
package net.bounceme.dur.client;
import java.util.concurrent.BlockingQueue;
public class Producer implements Runnable {
private final BlockingQueue<Message> queue;
public Producer(BlockingQueue<Message> q) {
this.queue = q;
}
#Override
public void run() {
//produce messages
for (int i = 0; i < 100; i++) {
Message msg = new Message("" + i);
try {
Thread.sleep(i);
queue.put(msg);
System.out.println("Produced " + msg.getMsg());
} catch (InterruptedException e) {
}
}
//adding exit message
Message msg = new Message("exit");
try {
queue.put(msg);
} catch (InterruptedException e) {
}
}
}
Would the Producer just handle getting objects from the socket connection via objectInputStream.readObject();, for example?
If so, how do I slow down the Producer (which, from a certain perspective, is also a consumer) so that it only "produces" one object at a time, waits to be notified, and then, only when notified, goes back to the stream for another object.
From within the context of the client, this is a producer, but, from a wider view, I suppose it's also a consumer.
How does the producer receive a semaphore, or other notification, to then "produce" another object?
Because Producer implements Runnable, I cannot pass parameters into run. Could, perhaps, the ProducerConsumerService driver pause the thread? That seems error-prone, at the least.
code borrowed from:
http://www.journaldev.com/1034/java-blockingqueue-example-implementing-producer-consumer-problem
Explicit answers not required -- I'm probably just misunderstanding how to use a BlockingQueue with Sockets. At present, I want to leave the server unchanged, so that its response/request "flow" of sending an object, and then waiting for a response, stays like that.
One solution is to use a size 1 ArrayBlockingQueue. The producer can only put one object at a time in there, and wait until the consumer removes it.
So the pseudocode would be something like...
// Producer thread (produces serverside data)
obj = readObjFromServer();
sharedQueue.put(obj); // Blocks if there is already an object waiting
// Consumer thread
obj = sharedQueue.take(); // Blocks until data available
handleData(obj);
There is a component in my application that listens to a server via TCP (so it only receives data, the output-stream is never used). The only reason for a potential disconnect are technical issues. From a logical point of view, the connection should stay open forever.
I know that I have to implement some kind of ping/pong strategy if I want to detect a connection failure immediately. But in my case, it is not necessary to detect a dropped connection immediately as long as it gets detected at all (let's say some minutes or hours later).
My questions:
If I don't use some kind of pingpong/alive-check strategy and the connection drops, will I get an IOException in my application logic some time later (it would be okay if it took some hours) or is it possible that the dropped connection isn't detected at all?
Would the code below fit my requirements? It's a bit ugly (many try-catch/while(true) and even sleep, but I'm wondering if a timed out connection could be recognized after a certain amount of time (e.g. due to an IOException in the blocking BufferedReader.readLine method).
Apart from the questions above, what could I do better?
public class Receiver implements Runnable {
private Socket socket;
private final String host;
private final int port;
private final int connectionRetryAfter = 10* 1000;
public Receiver(String host, int port) { // assignments... }
#Override
public void run() {
tryCreateSocket();
listenToServer();
}
private void listenToServer() {
String receivedLine;
BufferedReader buf;
while(true) {
try {
buf = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while ((receivedLine = buf.readLine()) != null) {
// do something with 'inputLine'
}
} catch (IOException e) {
// logging
} finally {
closeSocket();
}
// At this point, either an exception occured or the stream equals null (which means it's closed?)
tryCreateSocket();
}
}
private void tryCreateSocket() {
try {
socket = new Socket(host, port);
} catch (IOException e) {
// logging
try {
Thread.sleep(connectionRetryAfter);
} catch(InterruptedException ex) {
// logging
Thread.currentThread().interrupt();
}
// retry
tryCreateSocket();
}
}
private void closeSocket() {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
// logging
}
}
}
}
listenToServer() should certainly throw an IOException if the connection/reconnection attempt fails. Consider the case when the server is down. Do you really want to loop inside this method forever?
One problem you might need to avoid is that you tryCreateSocket() makes a recursive call. If your client is disconnected for a very long time you might run out of memory. Further more when you do reestablish connection the memory stack is not freed.
I would recommend an iterative while loop calling the tryCreateSocket() to avoid this problem.
I'm trying to use server sockets to set up a connection between a client and a server. I'm also not using java.nio.
The problem is that I'm constantly sending a test message, and detecting whether if it is successful in sending the message (the client is still connected), if not, then the client is disconnected.
Shown here:
try
{
Scanner in = new Scanner(socket.getInputStream());
BufferedReader in_2 = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while(stopThread)
{
if(in_2.ready())
{
String message = in_2.readLine();
dt = new DateTime();
PrintStream out = new PrintStream(socket.getOutputStream());
server.detect(message, dataSets, out);
dataSets.add(message);
GUI.textArea_1.append(message + "\r\n");
GUI.textArea_1.setCaretPosition(GUI.textArea_1.getDocument().getLength());
}
else
{
PrintStream out = new PrintStream(socket.getOutputStream());
out.println("Testing Connection \r\n");
if(out.checkError())
{
try
{
socket.close();
}
catch (IOException e)
{
e.printStackTrace();
}
stopThread = false;
GUI.textArea.append(userName + " disconnected \r\n");
GUI.textArea.setCaretPosition(GUI.textArea.getDocument().getLength());
server.inputDataForm(userName, dt, dataSets);
}
Thread.sleep(3000);
}
}
The problem is that the Thread.sleep(3000) is actually interfering with getting data, since after 3 seconds, I will get a huge amount of data (because I stopped the thread for 3 seconds).
Now, what I proposed is a anonymous class in the else statement.
class runThread implements runnable
{
void run()
{
//Put the else statement here
}
}
But the stopThread = false is not a constant, which I'm trying to control.
Other threads I've searched only puts variables inside main inside the anonymous class, but I need stopThread to stop the while loop if the client is disconnected.
Does anyone have an idea?
Thanks!
Consider setting a short timeout on your socket. This will allow you to control how long your thread will block while waiting for data from the socket.
If data are not quickly available, a very specific java.net.SocketTimeoutException will be raised. You can handle this exception by checking your stopThread flag. If it is set, you can return from the method. Otherwise, the socket is still valid and you can try another read operation with timeout.
If any other exception type is thrown, your socket is probably no longer valid.
socket.setSoTimeout(20); /* 1/50th of a second. */
BufferedReader in = new BufferedReader
(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
while (!stop) {
try {
String message = in.readLine();
if (message == null)
handleEOF();
else
handleMessage(message);
} catch(SocketTimeoutException ignore) {
/* Loop back to check "stop" flag. */
continue;
} catch(IOException ex) {
handleDisconnection();
break;
}
}
By the way, if you are using Swing, remember that you can only modify graphical components from Swing's Event Dispatch Thread, and you can't tie up the EDT in long-running operations like this socket handling. You should be passing tasks from this thread to Swing's invokeLater() utility.
Why don't you make a class that implements runnable but also has the method stop();
public class MyRunner implements Runnable(){
MutableBoolean stop = false;
public void run(){...}
public void stop(){
stop = true;
}
}
I am trying to keep a connection open for a multithreaded server program. When I hit a button, I want it to send a test message to all clients that are connected.
public void run() {
try {
Scanner in = new Scanner(socket.getInputStream());
PrintWriter out = new PrintWriter(socket.getOutputStream());
readUpdate(out, in);
while(true){sendUpdate(out);}
} catch (Exception e) {
e.printStackTrace();
}
}
Uses way to much CPU.
This is my sendUpdate method.
private void sendUpdate(final PrintWriter out) {
new Thread(new Runnable() {
public void run() {
if(Server.send) {
try {
if (Server.command != "idle") {
System.out.println("Sending");
out.println("!msg#" + Server.command);
out.flush();
Server.send = false;
Thread.sleep(100);
}
} catch (Exception ex) {
}
}
}
}).start();
}
If somebody can help me keep the connection open, and ready to send data, I would appreciate it.
If your server can initiate messages and so can your client, you probably want a separate thread reading and writing. One thread makes sense for request-response style communication, where you can block on the next client request, do some server-side processing, respond to the client, and then block again.
But if you need to block on two separate conditions (receiving a message from the client and you clicking the button on the server) then you should have two separate threads. Otherwise, you will find yourself needing to repeatedly wake your thread up to check if either of the conditions are true.
So create two threads, and give one your Scanner (that does the readUpdate logic) and the other your PrintWriter. This is what your output handler could look like:
public class WriteHandler implements Runnable {
private final PrintWriter out;
private final BlockingQueue<String> messageQueue = new LinkedBlockingQueue<String>();
//initialize the above in a constructor;
public void run() {
while(true) {
String nextMessageToWrite = messageQueue.poll();
out.println(nextMessageToWrite);
}
}
public void send(String message) {
messageQueue.add(message);
}
}
This uses a blocking queue, which is a much better concurrency mechanism than a check-sleep loop. Then when the button is clicked, you can just have something like this:
public void actionPerformed() {
for ( WriteHandler handler : handlers ) {
handler.send("PING!");
}
}