问题提出:
我编写的一个网页下载程序,网页下载中,有可能会断线而下载不成功。
所以可以启动一个定时器,定时器到还没有下载成功,需要重新下载该网页。
若在定时内下载成功,则可以下载另一个网页。程序流程如下,
主线程用来启动读网页线程,并启动定时器。然后等待读网页线程的完成。
如果定时器超时,则杀死或中断读线程,重新读该网页。如果读网页成功,则cancel 掉此定时器,
进入下一循环,读下一个网页。但碰到了如下问题。
1. 如果主线程等待读线程,(用join()) 则主线程就会阻塞。 怎样接受定时器
   溢出消息。即定时器超时后,怎样通知主线程。2. 如果主线程不阻塞,而是循环查询一个定时器设定的溢出标志。那读线程结束了
   又怎样通知主线程, 当然,可以再设另一标志,让主线程一块查。这样主
  线程就知道是定时器先溢出,还是读线程先结束。 不过我想这可能是最笨的
  办法了。要想使用变量通信,还得将定时器,读线程设置成内部类。
我想java 一定有处理此类问题的好办法。还请java 高手不吝赐教!在此先感谢了!!附我整理的针对此问题的代码帮助分析:请高手重点关注一下带???的三条语句import java.io.*;
import java.net.*;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Timer;
import java.util.TimerTask;public class TestGetHtml {  public static void main(String[] args) throws IOException {

// while(获取下一个连接,直到所有链接处理完毕,此处忽略){
String urllink1 = "http://www.baidu.com";  // for test only
while(true)  //读取网页,指导成功为止
{
// 启动读线程
Thread thread = new MyReadThread(urllink1);
thread.start();
// 启动定时器, 我不知道定时器怎样通知主线程 ????????????
MyTimer timer = new MyTimer(1000);  //设定超时时间,自己调整测试
timer.start();
// 等待读线程
try{
thread.join();    // 用join 等待可能不太好吧,但我不知道用什么方法。 ???????????
}
catch(InterruptedException e)
{
e.printStackTrace();
}
// 如果定时器超时,主线程要重新执行该循环,但我不知主线程怎样接受定时器消息 ?????????
// 如果读网页成功,则cancel 定时器,
System.out.println("Read html OK");
timer.stop();
break; //正常结束了,可以退出循环
}
// 忽略}
}
}class MyReadThread extends Thread
{ private static String urlName;
private static URL url;
private static URLConnection connection;
private static String type;
MyReadThread(String s)
{
urlName = s;
type = null;
url = null;
connection = null;
}
@Override
public void run()
{
System.out.println("connentting...");
connect(urlName); 
System.out.println("reading...");
readContents();
} static void connect( String urlString ) {
try {
url = new URL(urlString);
connection = url.openConnection();
//System.out.println(connection.getClass());
} catch (MalformedURLException e){
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

static void readContents() {
BufferedReader reader = null;
try {
reader = new BufferedReader( new InputStreamReader( connection.getInputStream()));
String inputLine;
while ( (inputLine = reader.readLine()) != null) 
{
System.out.println(inputLine);
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
}

}class MyTimer
{
int miliseconds;
Timer timer;
MyTimer(int miliseconds)
{
this.miliseconds = miliseconds;
}
public void start()
{
class MyTimerTask extends TimerTask{
@Override
public void run()
{
System.out.println("ha ha! time over .... reconnecting ...");
timer.cancel();
}
}
timer = new Timer();
timer.schedule(new MyTimerTask(), miliseconds);
System.out.println("start timer "+miliseconds);
}
public void stop()
{
// System.out.println("want stop timer");
timer.cancel(); // when has receive ok
}
}

解决方案 »

  1.   

    主线程就不要堵塞了吧,可否把定时器作为构造参数传给下载线程
    由下载线程去控制打开,出现异常就直接检查定时器状态 决定重试还是放弃
    同时要控制好线程数量,JAVA的连接 共享端口不怎么好用,容易出现无法分配端口
      

  2.   

    我的理解,java 定时器也是一个特殊的线程。 放到下载线程中也行,下载线程可能会被阻塞而超时。
    但超时的结果必需要通知主线程。反正主线程要知道是下载成功了还是超时了。我不知道主线程应该怎样知道。
    要是用C++ 就简单了。
    DWORD WaitForSingleObject(
      HANDLE hHandle,
      DWORD dwMilliseconds
    );根据返回值可以知道是WAIT_OBJECT_0, 或者WAIT_TIMEOUT。 但这里是java ,我不得,继续....
      

  3.   

    问题已经解决,帖子掉的真快啊!
    使用wait ,notify notifyAll,及共享数据已经解决。
    谢谢各位参与,分分。为保证信息完整,我把shareobject 代码贴出来class ShareObject
    {
    private boolean timeover;
    private boolean readhtmlok;
    ShareObject()
    {
    timeover = false;
    readhtmlok = false;
    }
    public synchronized void TimerOver()
    {
    timeover = true;
    notifyAll(); // 通知已经设好
    }
    public synchronized void ReadHtmlOK()
    {
    readhtmlok = true;
    notifyAll(); // 通知已经设好
    } public synchronized boolean GetReadResult()
    {
    if((timeover == false) && (readhtmlok == false))
    {
    try{
    wait(); //等待完成
    }
    catch(InterruptedException e)
    {
    e.printStackTrace();
    }
    }
    if(readhtmlok == true)
    {
    return true;
    }
    else if(timeover == true)
    {
    return false;  //read time over
    }
    else
    {
    System.out.println("I don't think will got here!");
    }
    return false;
    }
    }