当前位置:编程学习 > JAVA >>

困扰已久的俩个问题:线程执行超时的控制和怎么判断对象是否可以回收内存

困扰已久的俩个问题:希望大牛们排扰解难,非常感谢!
第一个:程执行超时的控制,像我们在eclipse里面启动tomcat,如果时间太长,会报Server Tomcat v6.0 Server at Tomcat6.0 was unable to start within 45 seconds. If the server requires more time, try increasing the timeout in the server editor. 这个错误是时间设太短导致的,我
想问一下这样的一个线程监控是怎么实现的,超过45S就自动中止了?线程的stop方法不建议使用,也实现不了这样的情况,而interrupt方法又不能中断正在运行的程序,我把tomcat的源码弄下来看了一下,也没有找到相关的代码,哪位帮助实现一下,或者源码也行。

第二个:怎么判断对象是否可以回收内存,对象没有被引用了就可以被回收了,我想知道用代码怎么来测试它是否可以被回收(或没有被引用了),JVM又是怎么判断的? 线程超时 回收内存  tomcat 启动 --------------------编程问答-------------------- 那个超时和你这里线程不是一个概念。你说线程的超时应该是执行时间吧。线程调用了start方法就启动了。
第二个问题我只是理论上知道原理,没去深究,回去研究下 --------------------编程问答-------------------- 第一个问题,搜了把,感觉这个挺靠谱的:http://tech.sina.com.cn/s/2008-07-04/1051720260.shtml

第二个问题,个人一些不成熟的理解,欢迎纠正:可回收的对象,这个概念就是没有指向这个对象的引用。假设存在一个测试方法来监控这个对象,那这个测试方法应该存在一个引用。这样就与产生一个矛盾了。虚拟机应该是通过<索引,内存地址>这样一个关系来管理内存的,当一个内存地址,没有任何一个索引指向它时,就可以被回收了。
欢迎纠正 --------------------编程问答-------------------- --------------------编程问答--------------------
引用 2 楼 oh_Maxy 的回复:
第一个问题,搜了把,感觉这个挺靠谱的:http://tech.sina.com.cn/s/2008-07-04/1051720260.shtml


关于线程超时的问题,其实timer也是另外启动一个线程去监听时间,那么如果每个线程都加一个timer,那么实际的线程数就变成原来的2倍,这样是不是很耗性能啊?有没有别的方式实现超时控制呢? --------------------编程问答--------------------
引用 4 楼 tiwerbao 的回复:
Quote: 引用 2 楼 oh_Maxy 的回复:

第一个问题,搜了把,感觉这个挺靠谱的:http://tech.sina.com.cn/s/2008-07-04/1051720260.shtml


关于线程超时的问题,其实timer也是另外启动一个线程去监听时间,那么如果每个线程都加一个timer,那么实际的线程数就变成原来的2倍,这样是不是很耗性能啊?有没有别的方式实现超时控制呢?


程序执行是串行的话,只有运行结束了才知道时间。想要在程序还未结束就计算超时,总需要有第三方来监控。 --------------------编程问答-------------------- 第二个问题。可以读读这个文章,虽然不知道从哪转来的:http://blog.csdn.net/originalcsdn/article/details/6269630 --------------------编程问答-------------------- 针对第二个问题:我敢肯定的是正常情况下,只要把对象引用设置为null,GC就会回收内存。 --------------------编程问答-------------------- 第一个问题, elcipse启动tomcat,tomcat不是作为JVM线程被启动。
tomcat是当作OS进程被启动的。
Linux的话,该进程是eclipse进程的子进程。
eclipse在启动“tomcat start”个Process的时候,另外启动一个计时线程,该线程sleep 45秒,等该线程醒来时,判断Process是否已返回,若未返回则报错。

第二个问题,在java里是干不了了。你得Hack JVM,
某些JVM是开源的,你可以拿来改,大部分JVM都是C/C++写的。 --------------------编程问答--------------------
引用 2 楼 oh_Maxy 的回复:
第一个问题,搜了把,感觉这个挺靠谱的:http://tech.sina.com.cn/s/2008-07-04/1051720260.shtml

第二个问题,个人一些不成熟的理解,欢迎纠正:可回收的对象,这个概念就是没有指向这个对象的引用。假设存在一个测试方法来监控这个对象,那这个测试方法应该存在一个引用。这样就与产生一个矛盾了。虚拟机应该是通过<索引,内存地址>这样一个关系来管理内存的,当一个内存地址,没有任何一个索引指向它时,就可以被回收了。
欢迎纠正



感谢回复, 第一问题的这个解决办法我试过的,这个异常是捕捉不到的。 --------------------编程问答--------------------
引用 8 楼 beowulf2005 的回复:
第一个问题, elcipse启动tomcat,tomcat不是作为JVM线程被启动。
tomcat是当作OS进程被启动的。
Linux的话,该进程是eclipse进程的子进程。
eclipse在启动“tomcat start”个Process的时候,另外启动一个计时线程,该线程sleep 45秒,等该线程醒来时,判断Process是否已返回,若未返回则报错。

第二个问题,在java里是干不了了。你得Hack JVM,
某些JVM是开源的,你可以拿来改,大部分JVM都是C/C++写的。


beowulf2005兄:能说更详细一点吗?像第一个,判断Process是否已返回,若未返回则报错,是怎样个原理,就是抛异常?服务又是怎样停的?相当于KILL掉了吗?

第二个问题:你有做过吗?能举个例子不?
--------------------编程问答-------------------- 第一个,
自己看下 process 文档
http://docs.oracle.com/javase/7/docs/api/java/lang/Process.html
destory的时候应该就算Kill,但有时候普通的kill信号kill不掉,还得自己kill -9

第二个,简单看过下文档,玩一下,没用它干过实际工作。一般也用不到就是了。
http://docs.oracle.com/javase/7/docs/technotes/guides/jvmti/
主要用来写Agent,基本上能监听到JVM的各种动作,JVM GC回收Object前,会发出ObjectFree事件。
你标注你关心的Object,然后Agent监听它,就知道那些Object什么时候被Free了。

另外写javaagent就已经可以满足通常监控的需要了。javaagent是java写的,比较容易写。
http://docs.oracle.com/javase/7/docs/api/java/lang/instrument/package-summary.html

--------------------编程问答--------------------
引用 9 楼 ai5173609 的回复:
Quote: 引用 2 楼 oh_Maxy 的回复:

第一个问题,搜了把,感觉这个挺靠谱的:http://tech.sina.com.cn/s/2008-07-04/1051720260.shtml

第二个问题,个人一些不成熟的理解,欢迎纠正:可回收的对象,这个概念就是没有指向这个对象的引用。假设存在一个测试方法来监控这个对象,那这个测试方法应该存在一个引用。这样就与产生一个矛盾了。虚拟机应该是通过<索引,内存地址>这样一个关系来管理内存的,当一个内存地址,没有任何一个索引指向它时,就可以被回收了。
欢迎纠正



感谢回复, 第一问题的这个解决办法我试过的,这个异常是捕捉不到的。

你说的对,确实捕捉不到。后来查阅了些资料,似乎没什么好办法直接中断一个线程。
后来考虑到事件的原子性,做了个demo,就是一个任务分成多个事件,每个事件执行前判断下是否超时,以此来判断是否需要继续执行下去。源码如下:


public class TestTimeout {

    public static void main(String[] args) {
        new Thread(new OneRun()).start();
    }
}

// 自定义线程
class OneRun implements Runnable {

    // 超时标记
    private boolean timeoutFLG = false;

    public synchronized void setTimoutFLG(boolean flg) {
        timeoutFLG = flg;
    }

    @Override
    public void run() {
        // 将多个原子操作间,通过超时标记判断是否超时
        int num = 0;
        System.out.println("我要做20件事情.");
        // 初始化一个监控线程来监控自己是否超时.时间设置为10秒
        TimeoutThread timeoutThread = new TimeoutThread(this, 10000);
        timeoutThread.start();
        try {
            while (!timeoutFLG && num++ < 20) {
                System.out.println("第" + num + "件事情开始...");
                // 每件时间耗时1秒
                Thread.sleep(1000);
                System.out.println("第" + num + "件事情结束.");
            }

            // 判断是否是正常结束
            if (timeoutFLG) {
                System.out.println("事情没做完啊,兄弟你超时了...");
                return;
            }
            System.out.println("事情都搞定了!");
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("花了10秒钟.");
    }
}

// 超时监控类
class TimeoutThread extends Thread {
    //   计时器超时时间
    private long   timeout;

    private OneRun oneRun;

    public TimeoutThread(OneRun oneRun, long timeout) {
        this.oneRun = oneRun;
        this.timeout = timeout;
    }

    @Override
    public void run() {
        try {
            System.out.println("---TimeoutThread.run---");
            System.out.println("---begin sleep---");
            // 超时了就设置超时标记
            Thread.sleep(timeout);
            oneRun.setTimoutFLG(true);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
--------------------编程问答-------------------- 超时的问题我试了一下Timer和TimerTast,是可以实现的,不过还没有研究它是怎么实现的,里面好像还有JVM的命令,有谁知道原理的请分享一下,多谢。 --------------------编程问答-------------------- 关于线程超时,楼主可以看看future  这个可以做类似于线程超时就返回的需求

另外对象回收,那是JVM的事情, 什么时候回收,怎么回收。。这也不可控啊。 --------------------编程问答-------------------- 天哪太恐怖了 --------------------编程问答--------------------
引用 13 楼 ai5173609 的回复:
超时的问题我试了一下Timer和TimerTast,是可以实现的,不过还没有研究它是怎么实现的,里面好像还有JVM的命令,有谁知道原理的请分享一下,多谢。


Timer 是JDK实现的一步分,源码不复杂,在你的JDK安装路径下就可以找到。
除了里面用到AtomicInteger之外,没有底层的东西。(AtomicInteger里有native方法封装了CPU指令)

java 线程模型是合作式线程模型。和Linux,Win等OS的竞争式进程管理模型不一样。
你在java里无法剥夺java线程的资源,除非他主动让出。
这些大学应该都教过啊。 --------------------编程问答--------------------
引用 12 楼 oh_Maxy 的回复:
Quote: 引用 9 楼 ai5173609 的回复:

Quote: 引用 2 楼 oh_Maxy 的回复:

第一个问题,搜了把,感觉这个挺靠谱的:http://tech.sina.com.cn/s/2008-07-04/1051720260.shtml

第二个问题,个人一些不成熟的理解,欢迎纠正:可回收的对象,这个概念就是没有指向这个对象的引用。假设存在一个测试方法来监控这个对象,那这个测试方法应该存在一个引用。这样就与产生一个矛盾了。虚拟机应该是通过<索引,内存地址>这样一个关系来管理内存的,当一个内存地址,没有任何一个索引指向它时,就可以被回收了。
欢迎纠正



感谢回复, 第一问题的这个解决办法我试过的,这个异常是捕捉不到的。

你说的对,确实捕捉不到。后来查阅了些资料,似乎没什么好办法直接中断一个线程。
后来考虑到事件的原子性,做了个demo,就是一个任务分成多个事件,每个事件执行前判断下是否超时,以此来判断是否需要继续执行下去。源码如下:


public class TestTimeout {

    public static void main(String[] args) {
        new Thread(new OneRun()).start();
    }
}

// 自定义线程
class OneRun implements Runnable {

    // 超时标记
    private boolean timeoutFLG = false;

    public synchronized void setTimoutFLG(boolean flg) {
        timeoutFLG = flg;
    }

    @Override
    public void run() {
        // 将多个原子操作间,通过超时标记判断是否超时
        int num = 0;
        System.out.println("我要做20件事情.");
        // 初始化一个监控线程来监控自己是否超时.时间设置为10秒
        TimeoutThread timeoutThread = new TimeoutThread(this, 10000);
        timeoutThread.start();
        try {
            while (!timeoutFLG && num++ < 20) {
                System.out.println("第" + num + "件事情开始...");
                // 每件时间耗时1秒
                Thread.sleep(1000);
                System.out.println("第" + num + "件事情结束.");
            }

            // 判断是否是正常结束
            if (timeoutFLG) {
                System.out.println("事情没做完啊,兄弟你超时了...");
                return;
            }
            System.out.println("事情都搞定了!");
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("花了10秒钟.");
    }
}

// 超时监控类
class TimeoutThread extends Thread {
    //   计时器超时时间
    private long   timeout;

    private OneRun oneRun;

    public TimeoutThread(OneRun oneRun, long timeout) {
        this.oneRun = oneRun;
        this.timeout = timeout;
    }

    @Override
    public void run() {
        try {
            System.out.println("---TimeoutThread.run---");
            System.out.println("---begin sleep---");
            // 超时了就设置超时标记
            Thread.sleep(timeout);
            oneRun.setTimoutFLG(true);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}


这种方式是自己停止,我也想到过,如果被分成的小事情还是很慢,或卡死,线程中止不了了。
可能真还要从操作系统的线程来处理了。 --------------------编程问答-------------------- 第一个实现可能的方式。起一个线程。
run(){
  while(启动没结束){
    if(超时){
      // log 
      System.exit(0);  // 结束jvm
    }
  }
  // 启动完毕,结束线程。
}
补充:Java ,  Java EE
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,