精华内容
下载资源
问答
  • AOP在JAVA多线程监控中的应用AOP在JAVA多线程监控中的应用AOP在JAVA多线程监控中的应用AOP在JAVA多线程监控中的应用AOP在JAVA多线程监控中的应用
  • 前言近期接到一个任务,需要改造...所以楼主花了3天的时间,利用java线程池框架Executors中的FixedThreadPool线程池重写了MTE导入工具,单台服务器导入效率提高十几倍(合理调整线程数据,效率更高)。关键技术栈Ela...

    前言

    近期接到一个任务,需要改造现有从mysql往Elasticsearch导入数据MTE(mysqlToEs)小工具,由于之前采用单线程导入,千亿数据需要两周左右的时间才能导入完成,导入效率非常低。所以楼主花了3天的时间,利用java线程池框架Executors中的FixedThreadPool线程池重写了MTE导入工具,单台服务器导入效率提高十几倍(合理调整线程数据,效率更高)。

    关键技术栈

    Elasticsearch

    jdbc

    ExecutorService\Thread

    sql

    工具说明

    maven依赖

    mysql

    mysql-connector-java

    ${mysql.version}

    org.elasticsearch

    elasticsearch

    ${elasticsearch.version}

    org.elasticsearch.client

    transport

    ${elasticsearch.version}

    org.projectlombok

    lombok

    ${lombok.version}

    com.alibaba

    fastjson

    ${fastjson.version}

    java线程池设置

    默认线程池大小为21个,可调整。其中POR为处理流程已办数据线程池,ROR为处理流程已阅数据线程池。

    privatestaticintTHREADS =21;

    publicstaticExecutorService POR = Executors.newFixedThreadPool(THREADS);

    publicstaticExecutorService ROR = Executors.newFixedThreadPool(THREADS);

    定义已办生产者线程/已阅生产者线程:ZlPendProducer/ZlReadProducer

    publicclassZlPendProducerimplementsRunnable {

    ...

    @Override

    publicvoidrun() {

    System.out.println(threadName + "::启动...");

    for(intj =0; j 

    try{

    ....

    intsize =1000;

    for(inti =0; i 

    if(i + size > count) {

    //作用为size最后没有100条数据则剩余几条newList中就装几条

    size = count - i;

    }

    String sql = "select * from "+ tableName +" limit "+ i +", "+ size;

    System.out.println(tableName + "::sql::"+ sql);

    rs = statement.executeQuery(sql);

    List lst = newArrayList<>();

    while(rs.next()) {

    HistPendingEntity p = PendUtils.getHistPendingEntity(rs);

    lst.add(p);

    }

    MteExecutor.POR.submit(newZlPendConsumer(lst));

    Thread.sleep(2000);

    }

    ....

    } catch(Exception e) {

    e.printStackTrace();

    }

    }

    }

    publicclassZlReadProducerimplementsRunnable {

    ...已阅生产者处理逻辑同已办生产者

    }

    定义已办消费者线程/已阅生产者线程:ZlPendConsumer/ZlReadConsumer

    publicclassZlPendConsumerimplementsRunnable {

    privateString threadName;

    privateList lst;

    publicZlPendConsumer(List lst) {

    this.lst = lst;

    }

    @Override

    publicvoidrun() {

    ...

    lst.forEach(v -> {

    try{

    String json = newGson().toJson(v);

    EsClient.addDataInJSON(json, Const.ES.HistPendDB_Index, Const.ES.HistPendDB_type, v.getPendingId(), null);

    Const.COUNTER.LD_P.incrementAndGet();

    } catch(Exception e) {

    e.printStackTrace();

    System.out.println("err::PendingId::"+ v.getPendingId());

    }

    });

    ...

    }

    }

    publicclassZlReadConsumerimplementsRunnable {

    //已阅消费者处理逻辑同已办消费者

    }

    定义导入Elasticsearch数据监控线程:Monitor

    监控线程-Monitor为了计算每分钟导入Elasticsearch的数据总条数,利用监控线程,可以调整线程池的线程数的大小,以便利用多线程更快速的导入数据。

    publicvoidmonitorToES() {

    newThread(() -> {

    while(true) {

    StringBuilder sb = newStringBuilder();

    sb.append("已办表数::").append(Const.TBL.TBL_PEND_COUNT)

    .append("::已办总数::").append(Const.COUNTER.LD_P_TOTAL)

    .append("::已办入库总数::").append(Const.COUNTER.LD_P);

    sb.append("~~~~已阅表数::").append(Const.TBL.TBL_READ_COUNT);

    sb.append("::已阅总数::").append(Const.COUNTER.LD_R_TOTAL)

    .append("::已阅入库总数::").append(Const.COUNTER.LD_R);

    if(ldPrevPendCount ==0&& ldPrevReadCount ==0) {

    ldPrevPendCount = Const.COUNTER.LD_P.get();

    ldPrevReadCount = Const.COUNTER.LD_R.get();

    start = System.currentTimeMillis();

    } else{

    longend = System.currentTimeMillis();

    if((end - start) /1000>=60) {

    start = end;

    sb.append("\n#########################################\n");

    sb.append("已办每分钟TPS::"+ (Const.COUNTER.LD_P.get() - ldPrevPendCount) +"条");

    sb.append("::已阅每分钟TPS::"+ (Const.COUNTER.LD_R.get() - ldPrevReadCount) +"条");

    ldPrevPendCount = Const.COUNTER.LD_P.get();

    ldPrevReadCount = Const.COUNTER.LD_R.get();

    }

    }

    System.out.println(sb.toString());

    try{

    Thread.sleep(3000);

    } catch(InterruptedException e) {

    e.printStackTrace();

    }

    }

    }).start();

    }

    初始化Elasticsearch:EsClient

    String cName = meta.get("cName");//es集群名字

    String esNodes = meta.get("esNodes");//es集群ip节点

    Settings esSetting = Settings.builder()

    .put("cluster.name", cName)

    .put("client.transport.sniff",true)//增加嗅探机制,找到ES集群

    .put("thread_pool.search.size",5)//增加线程池个数,暂时设为5

    .build();

    String[] nodes = esNodes.split(",");

    client = newPreBuiltTransportClient(esSetting);

    for(String node : nodes) {

    if(node.length() >0) {

    String[] hostPort = node.split(":");

    client.addTransportAddress(newTransportAddress(InetAddress.getByName(hostPort[0]), Integer.parseInt(hostPort[1])));

    }

    }

    初始化数据库连接

    conn = DriverManager.getConnection(url, user, password);

    启动参数

    nohup java -jar mte.jar ES-Cluster2019 node1:9300,node2:9300,node3:9300root123456! jdbc:mysql://ip:3306/mte 130 130 >> ./mte.log 2>&1 &

    参数说明

    ES-Cluster2019 为Elasticsearch集群名字

    node1:9300,node2:9300,node3:9300为es的节点IP

    130 130为已办已阅分表的数据

    程序入口:MteMain

    // 监控线程

    Monitor monitorService = newMonitor();

    monitorService.monitorToES();

    // 已办生产者线程

    Thread pendProducerThread = newThread(newZlPendProducer(conn,"ZlPendProducer"));

    pendProducerThread.start();

    // 已阅生产者线程

    Thread readProducerThread = newThread(newZlReadProducer(conn,"ZlReadProducer"));

    readProducerThread.start();

    【编辑推荐】

    展开全文
  • "><img title="Java多线程监控分析工具(VisualVM)/JConsole - ffwangkun@126 - 永恒的瞬间 " alt="" src="http://images.51cto.com/files/uploadimg/20120330/1125470.jpg" width="498"></p> <p>VisualVM是JDK的一个...

    http://zhaohe162.blog.163.com/blog/static/3821679720122314172834/

          </div>
        </div>
    
        <div>
    
        </div>
    
    
        <div><p>在Java多线程程序运行时,多数情况下我们不知道到底发生了什么,只有出了错误的日志的时候,我们才知道原来代码中有死锁。撇开代码检查工具,我们先讨论一下利用VisualVM监控,分析我们的多线程的运行情况。<strong>(注:实践本文内容的JDK的版本需要1.6.07以上)</strong></p> <p><strong>什么是VisualVM</strong></p> <div> <p style="text-align: center;"><img title="Java多线程监控分析工具(VisualVM)/JConsole - ffwangkun@126 - 永恒的瞬间 " alt="" src="http://images.51cto.com/files/uploadimg/20120330/1125470.jpg" width="498"></p> <p>VisualVM是JDK的一个集成的分析工具,自从JDK 6 Update 7以后已经作为Sun的JDK的一部分。</p> <p>VisualVM
    

    可以做的:监控应用程序的性能和内存占用情况、监控应用程序的线程、进行线程转储(Thread Dump)或堆转储(Heap
    Dump)、跟踪内存泄漏、监控垃圾回收器、执行内存和CPU分析,保存快照以便脱机分析应用程序;同时它还支持在MBeans上进行浏览和操作。尽管
    VisualVM自身要在JDK6以上的运行,但是JDK1.4以上版本的程序它都能被它监控。

    在JDK1.6.07以上的版本中:到$JAVA_HOME/bin,点击jvisualvm.exe图标就可以启动VisualVM;当然也可以点击这里获取官方的最新版本,支持:英文,中文,日文。

    VisualVM功能集成较多,我们这里只讨论它对象线程的监控分析。

    VisualVM监控线程


    我们运行VisualVM的时候,可以在应用程序》本地中看到VisualVM和eclipse的运行程序,然后我们启动eclipse中的一个
    线程:com.longtask.thread.TestVisualVm,可以看到在菜单中多了一个该线程的显示。点击右边的 线程
    菜单,可以看到线程运行的跟踪情况。

    点击 thread dump,可以生成该线程的运行情况的tdump文件,通过thread dump提供的相关信息,我们可以看到线程在什么地方被阻塞了以及线程的其他状态。

    把日志另存为文件,到Thread Dump Analyzer的主页点击图标下载TDA,然后用TDA打开刚才VisualVM保存的 thread dump文件,查看相关的分析结果。

    我们也可以用VisualVM来监控远程java线程的运行情况。

    远程监控:启动RMI服务

    1:新建一个jstatd.all.policy文件,在里面添加以下内容来保证jstatd服务启动的时候不报异常:

    1. grant codebase ”file:${java.home}/../lib/tools.jar"</span><span>&nbsp;{ &nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;permission&nbsp;java.security.AllPermission; &nbsp;</span></li><li><span>};&nbsp;</span></li></ol></pre> <p>2:netstat -ano | grep -i 1099 查看1099端口是否被占用了,如果被占用,则需要选择其他端口来启动jstatd服务</p> <p>3:如果端口被占用,用以下方式启动jstatd服务:</p> <pre><ol><li><span><span>rmiregistry&nbsp;</span><span>2020</span><span>&nbsp;&amp;&nbsp;jstatd&nbsp;-J-Djava.security.policy=jstatd.all.policy&nbsp;-p&nbsp;</span><span>2020</span><span>&nbsp;</span></span></li></ol></pre> <p>更多jstatd的文档请参考sun公司的官方文档 <a target="_blank" rel="nofollow" href="http://java.sun.com/j2se/1.5.0/docs/tooldocs/share/jstatd.html">这里</a></p> </div> <p><strong>远程监控Jboos服务</strong></p> <div> <p style="text-align: center;"><img title="Java多线程监控分析工具(VisualVM)/JConsole - ffwangkun@126 - 永恒的瞬间 " alt="" src="http://images.51cto.com/files/uploadimg/20120330/1125474.jpg" width="498"></p> <p>1:修改JDK下面的jmx的配置文件:</p> <p>切换至$JAVA_HOME所在目录/jre/lib/management下,

      I:将jmxremote.access、jmxremote.password.template权限调整为读写:

      1. grant codebase ”file:${java.home}/../lib/tools.jar"</span><span>&nbsp;{ &nbsp;</span></span></li><li><span>permission&nbsp;java.security.AllPermission; &nbsp;</span></li><li><span>};&nbsp;</span></li></ol></pre> <p>II:vi jmxremote.password去掉</p> <p># monitorRole QED</p> <p># controlRole R&amp;D</p> <p>的#号</p> <p>2:在Jboss的启动文件中添加以下信息:</p> <pre><ol><li><span><span>JAVA_OPTS="-Dcom.sun.management.jmxremote.port=</span><span>2899</span><span>&nbsp;\ &nbsp;</span></span></li><li><span>-Dcom.sun.management.jmxremote.ssl=</span><span>false</span><span>&nbsp;\ &nbsp;</span></li><li><span>-Dcom.sun.management.jmxremote.authenticate=</span><span>false</span><span>&nbsp;\ &nbsp;</span></li><li><span>-Djava.rmi.server.hostname=</span><span>10.212</span><span>.</span><span>20.9</span><span>&nbsp;&nbsp;其他配置"&nbsp;</span></li></ol></pre> <p>3:检查启动情况:</p> <p>netstat -a | grep -i 2899 查看端口占有情况</p> <p>如果2899端口被其他程序占用,在jboss配置文件中调整端口-Dcom.sun.management.jmxremote.port=****</p> <p>而后在VisualVM中就添加远程连接,选择jmx方式,就可以监控jboss的运行情况了。</p> <p><strong>参考文档:</strong></p> </div> <div> <p>1:<a target="_blank" rel="nofollow" href="http://java.sun.com/j2se/1.5.0/docs/tooldocs/share/jstatd.html">jstatd的帮助文档</a></p> <p>2:<a target="_blank" rel="nofollow" href="https://visualvm.dev.java.net/zh_CN/gettingstarted.html">VisualVM的帮助文档</a></p> <p>3:<a target="_blank" rel="nofollow" href="http://java.sun.com/javase/6/docs/technotes/guides/visualvm/jmx_connections.html">Java VisualVM 的文档</a></p> <p>4:<a target="_blank" rel="nofollow" href="http://blogs.sun.com/jmxetc/entry/troubleshooting_connection_problems_in_jconsole">JConsole的FAQ</a></p> <p>5:<a target="_blank" rel="nofollow" href="https://tda.dev.java.net/">Thread Dump Analyzer 帮助文档</a></p><p><br></p><p><br></p><p><br></p><p><b>JConsole</b></p><p><br>到$JAVA_HOME/bin,点击jconsole.exe图标就可以启动JConsole,
        Java多线程监控分析工具(VisualVM)/JConsole - ffwangkun@126 - 永恒的瞬间
        以tomcattomcat工程为例,选择org.apache..Bootstrap.start.点击链接

        Java多线程监控分析工具(VisualVM)/JConsole - ffwangkun@126 - 永恒的瞬间

        查看线程模块,可进一步观察细节
         



    展开全文
  • Java 多线程线程监控

    千次阅读 2016-07-22 12:09:14
    在程序开发中我们经常会使用到很多线程去做不同的业务,我们怎么能方便的管理这些线程呢?是否我们希望我们创建的线程能够一直运行下去,知道程序退出?在这里我们使用一个监控线程的概念。我们可以定义一个线程继承...

    在程序开发中我们经常会使用到很多线程去做不同的业务,我们怎么能方便的管理这些线程呢?是否我们希望我们创建的线程能够一直运行下去,知道程序退出?在这里我们使用一个监控线程的概念。

    我们可以定义一个线程继承自Thread类,在其中定义一个Map集合,用于存放我们需要管理的线程;当我们需要对某个线程进行操作时,我们就可以根据他的key值获取到;
    
    private HashMap<String, Thread> threads2Watch = new HashMap<String, Thread>();
    

    在run方法中,我们写一个循环,让此线程一直运行下去,并利用sleep方法,让其停顿一段时间;

    while (true) {
                try {
                    sleep(1 * 60 * 1000);
                } catch (InterruptedException e) {
                    DebugLog.logger.error("Exception!!", e);
                    continue;
                }
            }

    注意这里的catch中加入了一个continue;即使此次sleep发生了异常,while循环仍然可以运行下去;不会对整个线程造成影响;

    在while()循环中,我们就可以写自己管理线程的业务方法了,比如遍历整个map集合,获取当前线程的转态,如果线程已经结束,我们就从新开启一个这样的线程,并把它加入map集合中;

    通过以上的这种做法,我们可以让我们自己程序中想要一直运行的线程一直运行下去,这种线程尤其适合在频繁监听某一网络端口,网络状态,某些值的变化是很重要的;

    通过这种思想,我们可以根据自己需要扩展自己的功能;

    展开全文
  • Java多线程程序运行时,多数情况下我们不知道到底发生了什么,只有出了错误的日志的时候,我们才知道原来代码中有死锁。撇开代码检查工具,我们先讨论一下利用VisualVM监控,分析我们的多线程的运行情况。 AD:51...

    在Java多线程程序运行时,多数情况下我们不知道到底发生了什么,只有出了错误的日志的时候,我们才知道原来代码中有死锁。撇开代码检查工具,我们先讨论一下利用VisualVM监控,分析我们的多线程的运行情况。

    AD:51CTO学院:IT精品课程在线看!

    在Java多线程程序运行时,多数情况下我们不知道到底发生了什么,只有出了错误的日志的时候,我们才知道原来代码中有死锁。撇开代码检查工具,我们先讨论一下利用VisualVM监控,分析我们的多线程的运行情况。(注:实践本文内容的JDK的版本需要1.6.07以上)

    什么是VisualVM

    VisualVM是JDK的一个集成的分析工具,自从JDK 6 Update 7以后已经作为Sun的JDK的一部分。

    VisualVM可以做的:监控应用程序的性能和内存占用情况、监控应用程序的线程、进行线程转储(Thread Dump)或堆转储(Heap Dump)、跟踪内存泄漏、监控垃圾回收器、执行内存和CPU分析,保存快照以便脱机分析应用程序;同时它还支持在MBeans上进行浏览和操作。尽管 VisualVM自身要在JDK6以上的运行,但是JDK1.4以上版本的程序它都能被它监控。

    在JDK1.6.07以上的版本中:到$JAVA_HOME/bin,点击jvisualvm.exe图标就可以启动VisualVM;当然也可以点击这里获取官方的最新版本,支持:英文,中文,日文。

    VisualVM功能集成较多,我们这里只讨论它对象线程的监控分析。

    VisualVM监控线程

    当我们运行VisualVM的时候,可以在应用程序》本地中看到VisualVM和eclipse的运行程序,然后我们启动eclipse中的一个线程:com.longtask.thread.TestVisualVm,可以看到在菜单中多了一个该线程的显示。点击右边的 线程 菜单,可以看到线程运行的跟踪情况。

    点击 thread dump,可以生成该线程的运行情况的tdump文件,通过thread dump提供的相关信息,我们可以看到线程在什么地方被阻塞了以及线程的其他状态。

    把日志另存为文件,到Thread Dump Analyzer的主页点击图标下载TDA,然后用TDA打开刚才VisualVM保存的 thread dump文件,查看相关的分析结果。

    我们也可以用VisualVM来监控远程java线程的运行情况。

    远程监控:启动RMI服务

    1:新建一个jstatd.all.policy文件,在里面添加以下内容来保证jstatd服务启动的时候不报异常:

    1. grant codebase "file:${java.home}/../lib/tools.jar" {  
    2.     permission java.security.AllPermission;  
    3. }; 

    2:netstat -ano | grep -i 1099 查看1099端口是否被占用了,如果被占用,则需要选择其他端口来启动jstatd服务

    3:如果端口被占用,用以下方式启动jstatd服务:

    1. rmiregistry 2020 & jstatd -J-Djava.security.policy=jstatd.all.policy -p 2020 

    更多jstatd的文档请参考sun公司的官方文档 这里

    远程监控Jboos服务

    1:修改JDK下面的jmx的配置文件:

    切换至$JAVA_HOME所在目录/jre/lib/management下,

    I:将jmxremote.access、jmxremote.password.template权限调整为读写:

    1. grant codebase "file:${java.home}/../lib/tools.jar" {  
    2. permission java.security.AllPermission;  
    3. }; 

    II:vi jmxremote.password去掉

    # monitorRole QED

    # controlRole R&D

    的#号

    2:在Jboss的启动文件中添加以下信息:

    1. JAVA_OPTS="-Dcom.sun.management.jmxremote.port=2899 \  
    2. -Dcom.sun.management.jmxremote.ssl=false \  
    3. -Dcom.sun.management.jmxremote.authenticate=false \  
    4. -Djava.rmi.server.hostname=10.212.20.9  其他配置" 

    3:检查启动情况:

    netstat -a | grep -i 2899 查看端口占有情况

    如果2899端口被其他程序占用,在jboss配置文件中调整端口-Dcom.sun.management.jmxremote.port=****

    而后在VisualVM中就添加远程连接,选择jmx方式,就可以监控jboss的运行情况了。

    展开全文
  • 业务系统有线程在运行,为了防止线程挂掉,需要监控线程运行情况,在线程挂掉以后重新启动它。提示:先排错,再容错,这个方式只是用来兜底的。监控进程,遍历已经注册的线程,发现挂掉就重新创建并启动:import...
  • 日萌社 人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度学习实战(不定时更新)文章参考:https://www.jb51.net/article/116526.htmjava ScheduledExecutorService 多线程与定时任务的结合使用读取文件...
  • Java多线程--线程监控工具之Jconsole

    千次阅读 2017-09-07 14:22:57
    一、JConsole是什么  从Java 5开始 引入了 ...您可以轻松地使用 JConsole(或者,它更高端的 “近亲” VisualVM )来监控 Java 应用程序性能和跟踪 Java 中的代码。 二、如何启动JConsole 如果是从命令行启动,使
  • Java VisualVM 多线程监控分析工具

    千次阅读 2016-10-18 19:59:31
    %JAVA_HOME%/bin/jvisualvm.exe是多线程监控分析工具。可以监控内存泄露,跟踪垃圾回收,执行时内存、cpu分析,线程分析……    程序运行后会自动监控本机运行的java程序(Local标签下,远程服务器上的java程序...
  • Zabbix在线监控tomcat的线程数,因为线上没有配置jmx,所以使用jstack pid的方式获取thread线程。脚本结合zabbix的自动发现,可以实现个tomcat实例的自动发现配置。免去以后tomcat增加后一个个手动添加的烦恼。...
  • Java实现监控多线程状态的简单实例发布于 2020-5-26|复制链接下面小妖就为大家带来一篇Java实现监控多线程状态的简单实例。小妖觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小妖过来看看吧实例...
  • 实例如下:import java.util.concurrent.CountDownLatch;import java.util.concurrent.Executor;import java.util..../*** 测试监控类** @author**/public class WatchThread {/*** 测试函数** @throws Interrup...
  • Java线程超时监控

    2014-07-18 09:01:18
    讲解有关Java多线程运行时针对单个线程的执行超时监控机制,用于处理单个线程执行控制
  • 不正确的线程中止-StopStop:中止线程,并且清除监控器锁的信息,但是可能导致 线程安全问题,JDK不建议用。 Destroy: JDK未实现该方法。/*** @author simon*/public class StopThread extends Thread {private int i...
  • 多线程 线程的状态 1. NEW(图中初始状态):一个刚创建而未启动的线程处于该状态。由于一个线程实例只能被启动一次,因此一个线程只可能有一次处于该状态。 2. 可运行(RUNNABLE):表示处于改状态的线程可以被JVM...
  • Java多线程监控分析工具(VisualVM)

    千次阅读 2014-04-04 02:55:13
    Java多线程程序运行时,多数情况下我们不知道到底发生了什么,只有出了错误的日志的时候,我们才知道原来代码中有死锁。撇开代码检查工具,我们先讨论一下利用VisualVM监控,分析我们的多线程的运行情况。 AD:...
  • 谢邀,如果理解操作系统线程,就好理解Java线程了。如果理解操作系统进程,操作系统线程也比较好理解。操作系统进程不陌生吧?你的迅雷在下载《三国演义》,暴风影音在播放《水浒传》,这就是两个进程,可以同时运行...
  • Java线程状态 线程的五种状态 * 新建:new(时间很短) * 运行:runnable * 等待:waitting(无限期等待),timed waitting(限期等待) * 阻塞:blocked * 结束:terminated(时间很短) Jvm监控工具 一、...
  • 场景:需要启动多线程处理事情,而在所有事情做完之后,需要修改系统状态;那么如何判断所有线程(事情)都做完了呢?这就需要判断所有当前运行的线程状态了。import java.util.concurrent.CountDownLatch;import java...
  • java ScheduledExecutorService 多线程与定时任务的结合使用 读取文件、写出文件 请使用 字符缓冲流、字节缓冲流 File output = new File("/home/root/logs/output.log"); File readin = new File("...
  • java 多线程

    2020-09-22 17:32:48
    java 多线程 一、基础概念 1.进程:把一个任务或者应用成为一个进程,比如浏览器,QQ,微信等都是进程。 2.线程:进程中程序的执行单元,比如我们在QQ浏览空间的时候,后台还在进行聊天消息的监控,如果在浏览空间...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,328
精华内容 531
关键字:

java多线程监控

java 订阅