Solved

timing out a method

Posted on 2002-03-17
29
662 Views
Last Modified: 2007-11-27
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

0
Comment
Question by:benutzername
  • 12
  • 12
  • 3
  • +1
29 Comments
 
LVL 92

Expert Comment

by:objects
ID: 6875714
You can't really timeout a method.
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.
0
 
LVL 5

Expert Comment

by:LexZEUS
ID: 6876081
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.currentThread(),1000);
    try
      {
      mySocket.getInpuStream().read(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
0
 
LVL 92

Expert Comment

by:objects
ID: 6876090
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.
0
 

Author Comment

by:benutzername
ID: 6876213
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 :(
0
 

Author Comment

by:benutzername
ID: 6876257
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.
0
 
LVL 92

Expert Comment

by:objects
ID: 6876259
> 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.
0
 
LVL 92

Expert Comment

by:objects
ID: 6876263
Just call isAlive() if you want to know if a thread is still running.
0
 
LVL 92

Expert Comment

by:objects
ID: 6876315
Your example won't work. join() doesn't delete the thread, it just waits for it to finish.
0
 
LVL 92

Expert Comment

by:objects
ID: 6876321
The only way I can think of to 'timeout' a method is thru the use of interrupt().
0
 

Author Comment

by:benutzername
ID: 6876363
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...
0
 

Author Comment

by:benutzername
ID: 6876365
I will try it with a combination of interrupt() and setSoTimeout()...
0
 
LVL 92

Expert Comment

by:objects
ID: 6878218
> 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.
0
 

Author Comment

by:benutzername
ID: 6881472
>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
0
 
LVL 92

Expert Comment

by:objects
ID: 6881485
In the thread you are interrupting.

public void run()
{
   try
   {
      dostuff();
   }
   catch (InterruptedException ex)
   {
      // Someones interrupted me
   }
}
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 5

Expert Comment

by:LexZEUS
ID: 6881574
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?
0
 
LVL 92

Expert Comment

by:objects
ID: 6881585
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.
0
 
LVL 5

Expert Comment

by:LexZEUS
ID: 6881696
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...
0
 

Author Comment

by:benutzername
ID: 6882181
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.InterruptedException
        at java.lang.Object.wait(Native Method)
        at java.lang.Object.wait(Object.java:426)
        at sun.awt.AWTAutoShutdown.activateBlockerThread(AWTAutoShutdown.java:309)
        at sun.awt.AWTAutoShutdown.notifyThreadBusy(AWTAutoShutdown.java:146)
        at java.awt.EventQueue.initDispatchThread(EventQueue.java:654)
        at java.awt.EventQueue.postEvent(EventQueue.java:209)
        at java.awt.EventQueue.postEventPrivate(EventQueue.java:190)
        at java.awt.EventQueue.postEvent(EventQueue.java:164)
        at java.awt.EventQueue.invokeLater(EventQueue.java:757)
        at javax.swing.SwingUtilities.invokeLater(SwingUtilities.java:1142)
        at javax.swing.text.StyleContext.reclaim(StyleContext.java:431)
        at javax.swing.text.StyleContext.addAttribute(StyleContext.java:274)
        at javax.swing.text.html.StyleSheet.addAttribute(StyleSheet.java:541)
        at javax.swing.text.StyleContext$NamedStyle.addAttribute(StyleContext.java:1490)
        at javax.swing.text.StyleContext.addStyle(StyleContext.java:89)
        at javax.swing.text.html.StyleSheet.addRule(StyleSheet.java:978)
        at javax.swing.text.html.StyleSheet$CssParser.endRule(StyleSheet.java:3097)
        at javax.swing.text.html.CSSParser.parseRuleSet(CSSParser.java:256)
        at javax.swing.text.html.CSSParser.getNextStatement(CSSParser.java:161)
        at javax.swing.text.html.CSSParser.parse(CSSParser.java:136)
        at javax.swing.text.html.StyleSheet$CssParser.parse(StyleSheet.java:3005)
        at javax.swing.text.html.StyleSheet.loadRules(StyleSheet.java:303)
        at javax.swing.text.html.HTMLEditorKit.getStyleSheet(HTMLEditorKit.java:358)
        at javax.swing.text.html.HTMLEditorKit.createDefaultDocument(HTMLEditorKit.java:185)
        at javax.swing.JEditorPane.setEditorKit(JEditorPane.java:945)
        at javax.swing.JEditorPane.setContentType(JEditorPane.java:871)
        at javax.swing.JEditorPane.getStream(JEditorPane.java:696)
        at nkUtil.www.DownloadThread.downloadWWWPage(DownloadThread.java:73)
        at nkUtil.www.DownloadThread.run(DownloadThread.java:46)
        at java.lang.Thread.run(Thread.java:536)
0
 

Author Comment

by:benutzername
ID: 6882183
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
0
 

Author Comment

by:benutzername
ID: 6882195
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("downloadToStringException: " + 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(getStream(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
0
 

Author Comment

by:benutzername
ID: 6882207
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(getStream(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 "";
        }            
    }    
0
 
LVL 92

Expert Comment

by:objects
ID: 6884081
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.
0
 
LVL 1

Expert Comment

by:saurav17
ID: 6888032
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.
0
 

Author Comment

by:benutzername
ID: 6888353
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.
0
 
LVL 1

Expert Comment

by:saurav17
ID: 6888536
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.
0
 

Author Comment

by:benutzername
ID: 6889176
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.
0
 
LVL 92

Accepted Solution

by:
objects earned 200 total points
ID: 6889754
If you want to control the timeout then
1. you can't use JEditorPane's getStream() method, as you need control over making the connection.
2. you can't use URLConnection either as this does not allow you to specify the timeout.

Have a look at HTTPClient at http://www.innovation.ch/java/HTTPClient/
It provides far better control over your download.
0
 

Author Comment

by:benutzername
ID: 6890215
that's what i needed ! thanks a lot for that tip :)
0
 
LVL 92

Expert Comment

by:objects
ID: 6890246
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
array6 challenfge 6 65
array11 challenge 16 52
Systems talking to each other 5 110
Core Java. What output will be and why ? 6 58
For customizing the look of your lightweight component and making it look opaque like it was made of plastic.  This tip assumes your component to be of rectangular shape and completely opaque.   (CODE)
Java had always been an easily readable and understandable language.  Some relatively recent changes in the language seem to be changing this pretty fast, and anyone that had not seen any Java code for the last 5 years will possibly have issues unde…
Viewers learn about the “while” loop and how to utilize it correctly in Java. Additionally, viewers begin exploring how to include conditional statements within a while loop and avoid an endless loop. Define While Loop: Basic Example: Explanatio…
Viewers will learn one way to get user input in Java. Introduce the Scanner object: Declare the variable that stores the user input: An example prompting the user for input: Methods you need to invoke in order to properly get  user input:

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

8 Experts available now in Live!

Get 1:1 Help Now