benutzername
asked on
timing out a method
hi,
I have a method, that gets a website as a String. Sometimes this method hangs, so i want to construct a timeout.
So if I call the method and it doesn't deliver the page within x seconds the program shall abort the download and continue its work.
this is a general problem, so an improved download method will help me, but won't fix the abstract problem itself...
So: how can I timeout a method-call ?
Ben Utzer
I have a method, that gets a website as a String. Sometimes this method hangs, so i want to construct a timeout.
So if I call the method and it doesn't deliver the page within x seconds the program shall abort the download and continue its work.
this is a general problem, so an improved download method will help me, but won't fix the abstract problem itself...
So: how can I timeout a method-call ?
Ben Utzer
Apart from objects sugestion, maybe you can play with this code.. but I don't have idea this will work or not..
public class Something
{
...
public void do readFromSocket()
{
TimerThread = new TimerThread(Thread.current Thread(),1 000);
try
{
mySocket.getInpuStream().r ead(buffer );
}
catch (Exception ex)
{
System.out.println("I/O error or unable to read from socket in 1 second");
}
}
...
}
public class TimerThread extends Thread
{
Thread td;
int waitTime;
TimerThread(Thread t, int time)
{
td = t;
waitTime = time;
start();
}
public void run()
{
try {
sleep(time);
td.interrupt();
}
catch (Exception ex) { }
}
}
Basically, the idea is to interrupt read(buffer) in 1000msec (1 sec).
Will this work? I dunno .. coz' I myself never try..
Alex
public class Something
{
...
public void do readFromSocket()
{
TimerThread = new TimerThread(Thread.current
try
{
mySocket.getInpuStream().r
}
catch (Exception ex)
{
System.out.println("I/O error or unable to read from socket in 1 second");
}
}
...
}
public class TimerThread extends Thread
{
Thread td;
int waitTime;
TimerThread(Thread t, int time)
{
td = t;
waitTime = time;
start();
}
public void run()
{
try {
sleep(time);
td.interrupt();
}
catch (Exception ex) { }
}
}
Basically, the idea is to interrupt read(buffer) in 1000msec (1 sec).
Will this work? I dunno .. coz' I myself never try..
Alex
I don't think you can interrupt a blocked read so I don't think that'll work, but setting the socket timeout will have basically the same effect.
ASKER
interrupt only sets the interrupt flag - you can read this flag with isInterrupted() - so it doesn`t really interrupt anything. the socket timeout will help me for the special problem of the connection, but the abstract problem still exists: how to kill a thread ?
imagine, you have a multithreading program, that has to run for weeks without crashing. you want to build a supervisor that scans all running threads from time to time. if one of the threads crashed, the supervisor will delete the thread and start a new thread to replace the crashed one - thats what i have to work out.
it seems, that sometimes the garbage collection doesn't work like it should, because sometimes a thread is kicked out by java, because of low memory, even if there would be enough memory if java just did some more garbage collection :(
imagine, you have a multithreading program, that has to run for weeks without crashing. you want to build a supervisor that scans all running threads from time to time. if one of the threads crashed, the supervisor will delete the thread and start a new thread to replace the crashed one - thats what i have to work out.
it seems, that sometimes the garbage collection doesn't work like it should, because sometimes a thread is kicked out by java, because of low memory, even if there would be enough memory if java just did some more garbage collection :(
ASKER
I found a soloution myself in between:
public class Test implements Runnable {
public long lastActionPerformed;
public Test() {
start();
}
public void run() {
while(true) {
lastActionPerformed = System.currentMillis();
// now do something
// ....
}
}
}
The thread t will be supervised by another thread. The other thread will check lastActionPerformed from time to time - if last action is too long ago (over 5000ms), it will delete the thread through Thread.join(whenToJoin) and construct a new one as replacement.
public class Supervisor implements Runnable {
private Thread t;
public static void main (String args[]) {
Thread s = new Thread(new Supervisor());
}
public Supervisor() {
t = new Thread(new Test());
start();
}
public void run() {
while(true) {
if ( System.currentMillis() - t.lastActionPerformed > 5000 ) {
t.join(1);
t = new Thread(new Test());
}
}
}
}
...hope this will work, didn't check the syntax in java - but the concept will work.
public class Test implements Runnable {
public long lastActionPerformed;
public Test() {
start();
}
public void run() {
while(true) {
lastActionPerformed = System.currentMillis();
// now do something
// ....
}
}
}
The thread t will be supervised by another thread. The other thread will check lastActionPerformed from time to time - if last action is too long ago (over 5000ms), it will delete the thread through Thread.join(whenToJoin) and construct a new one as replacement.
public class Supervisor implements Runnable {
private Thread t;
public static void main (String args[]) {
Thread s = new Thread(new Supervisor());
}
public Supervisor() {
t = new Thread(new Test());
start();
}
public void run() {
while(true) {
if ( System.currentMillis() - t.lastActionPerformed > 5000 ) {
t.join(1);
t = new Thread(new Test());
}
}
}
}
...hope this will work, didn't check the syntax in java - but the concept will work.
> interrupt only sets the interrupt flag
In the general case, interrupt() will cause the thread to throw an InterruptedException so it can be used to break a thread.
> if one of the threads crashed
If a thread is crashed then it is no longer running.
You just need to start a new one.
In the general case, interrupt() will cause the thread to throw an InterruptedException so it can be used to break a thread.
> if one of the threads crashed
If a thread is crashed then it is no longer running.
You just need to start a new one.
Just call isAlive() if you want to know if a thread is still running.
Your example won't work. join() doesn't delete the thread, it just waits for it to finish.
The only way I can think of to 'timeout' a method is thru the use of interrupt().
ASKER
API about join(long milliseconds): "Waits at most millis milliseconds for this thread to die."
What happens, if the thread doesn't die within the timerange of "milliseconds" ?
isAlive won't help me either - the thread is not "crashed" in the sense of "passed off" but "crashed" in the sense of "hanging in some point without continueing its work".
I find hanging threads by checking their lastActionPerformed variable.
It's a pitty, that sun didn't implement Thread.destroy() yet...
What happens, if the thread doesn't die within the timerange of "milliseconds" ?
isAlive won't help me either - the thread is not "crashed" in the sense of "passed off" but "crashed" in the sense of "hanging in some point without continueing its work".
I find hanging threads by checking their lastActionPerformed variable.
It's a pitty, that sun didn't implement Thread.destroy() yet...
ASKER
I will try it with a combination of interrupt() and setSoTimeout()...
> What happens, if the thread doesn't die within the timerange of "milliseconds" ?
Then the join method simply returns.
> "hanging in some point without continueing its work".
Threads hang for a variety of well defined reasons such as blocking I/O, sleep, wait etc.
Most of these can be awoken by an interrupt().
> I find hanging threads by checking their lastActionPerformed variable.
Yes, but then how do you stop them.
> It's a pitty, that sun didn't implement Thread.destroy() yet...
You can stop a thread, but it's prone to deadlocks and is not recomended.
Then the join method simply returns.
> "hanging in some point without continueing its work".
Threads hang for a variety of well defined reasons such as blocking I/O, sleep, wait etc.
Most of these can be awoken by an interrupt().
> I find hanging threads by checking their lastActionPerformed variable.
Yes, but then how do you stop them.
> It's a pitty, that sun didn't implement Thread.destroy() yet...
You can stop a thread, but it's prone to deadlocks and is not recomended.
ASKER
>In the general case, interrupt() will cause the thread to throw an InterruptedException so it can be
used to break a thread.
Where do I have to put the try-catch to catch the InterruptedException ? I tried it everywhere, but I don't find out, where to catch it :(
best regards,
Ben Utzer
used to break a thread.
Where do I have to put the try-catch to catch the InterruptedException ? I tried it everywhere, but I don't find out, where to catch it :(
best regards,
Ben Utzer
In the thread you are interrupting.
public void run()
{
try
{
dostuff();
}
catch (InterruptedException ex)
{
// Someones interrupted me
}
}
public void run()
{
try
{
dostuff();
}
catch (InterruptedException ex)
{
// Someones interrupted me
}
}
I thought interrupt() only interrupt when a thread in sleep() or wait() condition, it doesn't interrupt a thread which is not in one of above condition?
That is correct. I thought we were dealing with blocked threads.
If the thread is executing there is no (safe) way to stop it. If this is required then the thread should provide a mechanism for halting itself.
If the thread is executing there is no (safe) way to stop it. If this is required then the thread should provide a mechanism for halting itself.
yes I agree.. The thread itself should implements some mechanism to exit from run() method for garbage collection.
....
public boolean forcedToStop = false;
public void run()
{
while(!forcedToStop)
{
if (!forcedToStop) doSomethingPartOne();
if (!forcedToStop) doSomethingPartTwo();
if (!forcedToStop) doSomethingPartThree();
if (!forcedToStop) doSomethingPartAndSoOn();
// give another thread chance to execute
if (!forcedToStop)
try {sleep(100);} catch (Exception ex) { }
}
}
....
To stop the thread:
if (myThread.isAlive())
{
myThread.forcedToStop = true;
myThread.interrupt();
myThread=null; // for further garbage collection
}
The only way to stop thread instantly (but not recommended) is using _yourThread_.stop() method...
....
public boolean forcedToStop = false;
public void run()
{
while(!forcedToStop)
{
if (!forcedToStop) doSomethingPartOne();
if (!forcedToStop) doSomethingPartTwo();
if (!forcedToStop) doSomethingPartThree();
if (!forcedToStop) doSomethingPartAndSoOn();
// give another thread chance to execute
if (!forcedToStop)
try {sleep(100);} catch (Exception ex) { }
}
}
....
To stop the thread:
if (myThread.isAlive())
{
myThread.forcedToStop = true;
myThread.interrupt();
myThread=null; // for further garbage collection
}
The only way to stop thread instantly (but not recommended) is using _yourThread_.stop() method...
ASKER
i have no luck :( it seems that the exception is already catched within suns code, so it doesn't get down to my code and a can't catch and process it.
My classes are "Download" and "DownloadThread". Download starts a DownloadThread and gives it an URL. If DownloadThread hasn't completed after x seconds, it will be interrupted. But the exception is caught by something called "AWT blocker activation" ... whatever that is:
AWT blocker activation interrupted:
java.lang.InterruptedExcep tion
at java.lang.Object.wait(Nati ve Method)
at java.lang.Object.wait(Obje ct.java:42 6)
at sun.awt.AWTAutoShutdown.ac tivateBloc kerThread( AWTAutoShu tdown.java :309)
at sun.awt.AWTAutoShutdown.no tifyThread Busy(AWTAu toShutdown .java:146)
at java.awt.EventQueue.initDi spatchThre ad(EventQu eue.java:6 54)
at java.awt.EventQueue.postEv ent(EventQ ueue.java: 209)
at java.awt.EventQueue.postEv entPrivate (EventQueu e.java:190 )
at java.awt.EventQueue.postEv ent(EventQ ueue.java: 164)
at java.awt.EventQueue.invoke Later(Even tQueue.jav a:757)
at javax.swing.SwingUtilities .invokeLat er(SwingUt ilities.ja va:1142)
at javax.swing.text.StyleCont ext.reclai m(StyleCon text.java: 431)
at javax.swing.text.StyleCont ext.addAtt ribute(Sty leContext. java:274)
at javax.swing.text.html.Styl eSheet.add Attribute( StyleSheet .java:541)
at javax.swing.text.StyleCont ext$NamedS tyle.addAt tribute(St yleContext .java:1490 )
at javax.swing.text.StyleCont ext.addSty le(StyleCo ntext.java :89)
at javax.swing.text.html.Styl eSheet.add Rule(Style Sheet.java :978)
at javax.swing.text.html.Styl eSheet$Css Parser.end Rule(Style Sheet.java :3097)
at javax.swing.text.html.CSSP arser.pars eRuleSet(C SSParser.j ava:256)
at javax.swing.text.html.CSSP arser.getN extStateme nt(CSSPars er.java:16 1)
at javax.swing.text.html.CSSP arser.pars e(CSSParse r.java:136 )
at javax.swing.text.html.Styl eSheet$Css Parser.par se(StyleSh eet.java:3 005)
at javax.swing.text.html.Styl eSheet.loa dRules(Sty leSheet.ja va:303)
at javax.swing.text.html.HTML EditorKit. getStyleSh eet(HTMLEd itorKit.ja va:358)
at javax.swing.text.html.HTML EditorKit. createDefa ultDocumen t(HTMLEdit orKit.java :185)
at javax.swing.JEditorPane.se tEditorKit (JEditorPa ne.java:94 5)
at javax.swing.JEditorPane.se tContentTy pe(JEditor Pane.java: 871)
at javax.swing.JEditorPane.ge tStream(JE ditorPane. java:696)
at nkUtil.www.DownloadThread.downloadWWWPage(DownloadThread.java:73)
at nkUtil.www.DownloadThread.run(DownloadThread.java:46)
at java.lang.Thread.run(Threa d.java:536 )
My classes are "Download" and "DownloadThread". Download starts a DownloadThread and gives it an URL. If DownloadThread hasn't completed after x seconds, it will be interrupted. But the exception is caught by something called "AWT blocker activation" ... whatever that is:
AWT blocker activation interrupted:
java.lang.InterruptedExcep
at java.lang.Object.wait(Nati
at java.lang.Object.wait(Obje
at sun.awt.AWTAutoShutdown.ac
at sun.awt.AWTAutoShutdown.no
at java.awt.EventQueue.initDi
at java.awt.EventQueue.postEv
at java.awt.EventQueue.postEv
at java.awt.EventQueue.postEv
at java.awt.EventQueue.invoke
at javax.swing.SwingUtilities
at javax.swing.text.StyleCont
at javax.swing.text.StyleCont
at javax.swing.text.html.Styl
at javax.swing.text.StyleCont
at javax.swing.text.StyleCont
at javax.swing.text.html.Styl
at javax.swing.text.html.Styl
at javax.swing.text.html.CSSP
at javax.swing.text.html.CSSP
at javax.swing.text.html.CSSP
at javax.swing.text.html.Styl
at javax.swing.text.html.Styl
at javax.swing.text.html.HTML
at javax.swing.text.html.HTML
at javax.swing.JEditorPane.se
at javax.swing.JEditorPane.se
at javax.swing.JEditorPane.ge
at nkUtil.www.DownloadThread.downloadWWWPage(DownloadThread.java:73)
at nkUtil.www.DownloadThread.run(DownloadThread.java:46)
at java.lang.Thread.run(Threa
ASKER
You might wonder, what JEditorPane has to to with my DownloadThread - it's like that:
I tried many different code samples for retrieving a web page over http, but most of them were refused by some servers, because they didn't know how to identify correctly.
JEditorPane is able to deliver an InputStream to download a HTML-Document and is not refused by any server, whoever.
Ben Utzer
I tried many different code samples for retrieving a web page over http, but most of them were refused by some servers, because they didn't know how to identify correctly.
JEditorPane is able to deliver an InputStream to download a HTML-Document and is not refused by any server, whoever.
Ben Utzer
ASKER
This is the source, I'm struggling with:
import java.net.URL;
public class Download {
/** Creates new Download */
public Download() {
}
//------------------------ ---------- ---------- ---------- ---------- ----------
// Interface
public String downloadToString(URL url, long timeout) {
try {
long startTime = System.currentTimeMillis() ;
DownloadThread d = new DownloadThread(url);
Thread t = new Thread(d);
t.start();
while(d.getResult() == null) {
if ((System.currentTimeMillis () - startTime) > timeout) {
t.interrupt();
break;
} else {
try{ wait(100);} catch(Exception e) {}
}
}
return d.getResult();
} catch (Exception e) {
System.out.println("downlo adToString Exception: " + e);
return null;
}
}
}
-------------------------- ---------- ---------- ---------- -
import java.net.*;
import java.io.*;
import javax.swing.JEditorPane;
class DownloadThread extends JEditorPane implements Runnable
{
//------------------------ ---------- ---------- ---------- ---------- ----------
// Felder
// read buffer size
private static int READ_BLOCK_SIZE = 128;
private char[] inputBuffer = new char[READ_BLOCK_SIZE];
private int charsRead;
//
private URL url;
private String result = null;
//------------------------ ---------- ---------- ---------- ---------- ----------
// Konstruktor
public DownloadThread(URL url) {
this.url = url;
}
//------------------------ ---------- ---------- ---------- ---------- ----------
// runtime
public void run() {
result = downloadWWWPage(url);
}
//------------------------ ---------- ---------- ---------- ---------- ----------
// Interface
public String getResult() {
return result;
}
//------------------------ ---------- ---------- ---------- ---------- ----------
// Download
private String downloadWWWPage(URL url) {
StringBuffer result = new StringBuffer();
InputStreamReader in = new InputStreamReader(getStrea m(url));
while(true) {
charsRead = in.read(inputBuffer, 0, READ_BLOCK_SIZE);
if (charsRead == -1) {
break;
} else {
result.append(inputBuffer, 0, charsRead);
}
}
// result
return result.toString();
}
}
-------------------------- ---------- ---------- ---------- ---
It's the best working web-document download routine I found yet, but it still has this interruption problem.
I'm building a spider, so I will need the best web-document download routine available, I gotta work hard on that issue.
Ben Utzer
import java.net.URL;
public class Download {
/** Creates new Download */
public Download() {
}
//------------------------
// Interface
public String downloadToString(URL url, long timeout) {
try {
long startTime = System.currentTimeMillis()
DownloadThread d = new DownloadThread(url);
Thread t = new Thread(d);
t.start();
while(d.getResult() == null) {
if ((System.currentTimeMillis
t.interrupt();
break;
} else {
try{ wait(100);} catch(Exception e) {}
}
}
return d.getResult();
} catch (Exception e) {
System.out.println("downlo
return null;
}
}
}
--------------------------
import java.net.*;
import java.io.*;
import javax.swing.JEditorPane;
class DownloadThread extends JEditorPane implements Runnable
{
//------------------------
// Felder
// read buffer size
private static int READ_BLOCK_SIZE = 128;
private char[] inputBuffer = new char[READ_BLOCK_SIZE];
private int charsRead;
//
private URL url;
private String result = null;
//------------------------
// Konstruktor
public DownloadThread(URL url) {
this.url = url;
}
//------------------------
// runtime
public void run() {
result = downloadWWWPage(url);
}
//------------------------
// Interface
public String getResult() {
return result;
}
//------------------------
// Download
private String downloadWWWPage(URL url) {
StringBuffer result = new StringBuffer();
InputStreamReader in = new InputStreamReader(getStrea
while(true) {
charsRead = in.read(inputBuffer, 0, READ_BLOCK_SIZE);
if (charsRead == -1) {
break;
} else {
result.append(inputBuffer,
}
}
// result
return result.toString();
}
}
--------------------------
It's the best working web-document download routine I found yet, but it still has this interruption problem.
I'm building a spider, so I will need the best web-document download routine available, I gotta work hard on that issue.
Ben Utzer
ASKER
ooopps, there was an error in the downloadWWWPage() - here is an update:
---------------------
private String downloadWWWPage(URL url) {
try {
StringBuffer result = new StringBuffer();
InputStreamReader in = new InputStreamReader(getStrea m(url));
while(true) {
charsRead = in.read(inputBuffer, 0, READ_BLOCK_SIZE);
if (charsRead == -1) {
break;
} else {
result.append(inputBuffer, 0, charsRead);
}
}
// result
return result.toString();
} catch (Exception e) {
return "";
}
}
---------------------
private String downloadWWWPage(URL url) {
try {
StringBuffer result = new StringBuffer();
InputStreamReader in = new InputStreamReader(getStrea
while(true) {
charsRead = in.read(inputBuffer, 0, READ_BLOCK_SIZE);
if (charsRead == -1) {
break;
} else {
result.append(inputBuffer,
}
}
// result
return result.toString();
} catch (Exception e) {
return "";
}
}
The actual connection to the server appears to be being handled in a seperate thread ie. not the one your interrupting. I'd say the thread you are interrupting is in fact just waiting on the connection to complete.
Also worth mentioning that you cannot interrupt blocked I/O.
Also worth mentioning that you cannot interrupt blocked I/O.
Hi benutzername,
Your problem is lying inside downloadwwwpage(url).
pass ur timeout value to this method. inside ur while validate ur timeout time. if u exceed the specified time come out of while loop, then ur download gets aborted.
Regards,
K.J.S.
Your problem is lying inside downloadwwwpage(url).
pass ur timeout value to this method. inside ur while validate ur timeout time. if u exceed the specified time come out of while loop, then ur download gets aborted.
Regards,
K.J.S.
ASKER
sorry, that doesn't work, because sometimes it takes hours to receive one block (to finish one loop) - in what case I would like to interrupt and cancel the transfer.
hi benutzername,
now I'm totally lost.
when u r not sure of the length of the process why do u want to give timeout.
Pls., clear me where do u need timeout here and for what purpose. So, that I may help u out.
Regards,
K.J.S.
now I'm totally lost.
when u r not sure of the length of the process why do u want to give timeout.
Pls., clear me where do u need timeout here and for what purpose. So, that I may help u out.
Regards,
K.J.S.
ASKER
ok, I will describe my situation in detail:
I'm programming a webcrawler. I start with a given URL (let's say "http://directory.google.com/"), download the HTML-Document, search the HTML-Source for any hyperlinks and store all the links into a database.
Then I get the next URL from the database, download it, write all links into the database and so on...
It happens, that a URL doesn't work correctly, in which case my webcrawler "hangs". For example, some servers just stop sending data, so that the line
charsRead = in.read(inputBuffer, 0, READ_BLOCK_SIZE);
will take forever.
I need a VERY robust download algorhithm, that doesn't hang on bad servers. It should time out after let's say 30 seconds, just forget the current download and continue with the next URL.
If anyone needs my webcrawler code, I have no problem with sharing it, its an noncommercial research project. The crawler works very good and is quite elaborate now (except for the download thread...). So if somebody else is working on a crawler, too, we could exchange our code.
I'm programming a webcrawler. I start with a given URL (let's say "http://directory.google.com/"), download the HTML-Document, search the HTML-Source for any hyperlinks and store all the links into a database.
Then I get the next URL from the database, download it, write all links into the database and so on...
It happens, that a URL doesn't work correctly, in which case my webcrawler "hangs". For example, some servers just stop sending data, so that the line
charsRead = in.read(inputBuffer, 0, READ_BLOCK_SIZE);
will take forever.
I need a VERY robust download algorhithm, that doesn't hang on bad servers. It should time out after let's say 30 seconds, just forget the current download and continue with the next URL.
If anyone needs my webcrawler code, I have no problem with sharing it, its an noncommercial research project. The crawler works very good and is quite elaborate now (except for the download thread...). So if somebody else is working on a crawler, too, we could exchange our code.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
that's what i needed ! thanks a lot for that tip :)
Sounds like what you want to do is is instead implement a timeout on your comms. Have a look at setSoTimeout() method in Socket class.