接着上一篇《线程安全扫盲贴三》,开始第二次测试。
第二次测试
这次并发1000个客户端消息,每次并发20条后休眠1秒。客户端消息发给我的Server后,我的Server再转发给消息指定的服务器。为了产生异常消息,我将指定的目标服务器关闭了,于是每次消息第一次发送完成后,都成为了一个异常消息,每个异常消息将会自动间隔30s;1m;2m发送3次,发送失败后停止发送。
这样虽然是并发了1000个,但是服务器实际发送了4000次。
张上一篇中已经看过这4个线程。此图与上一篇中,最明显的就是4个线程都在分时执行了,《线程安全扫盲贴三》只有2个在执行。新加入的2个就是异常消息errorList与异常文件删除监听的两个线程。
下面看看我的线程池,我有两个线程池,一个用来执行接收到的消息,一个用来发送消息。
接收到的消息进入接收的线程池中,分析消息内容,如果需要发送出去,再加入到发送的线程池中。
根据日志打印的结果,pool-1是发送消息的线程,pool2是接收消息的线程。
基本上pool1发送消息线程在执行的时候,pool2接收消息线程全部在等待。
上面这句话也许不对,pool1发送消息可以很多一起并发,多个发送线程间可能无资源抢占,pool2接收消息线程不能多个并发,这也可能造成这样。
执行了一段时间之后,发现待重发的消息并没有重发,同时4个监听线程显示只有Thread3在执行了,4巨头线程另外三个都在sleeping。
查看日志发现这几个线程分别对应的监听为:
Thread-0:已发送消息删除磁盘文件监听
Thread-1:已发送错误消息删除磁盘文件监听
Thread-2:待发送消息监听
Thread-3:待重发错误消息监听
这么看情况还是很乐观的,我正希望Thread-3是在运行可以将待重发的错误消息重发出去,虽然visual vm显示Thread-3在努力的running,但是下面是Thread-3的run方法,它连心跳的那句debug都无法打出来。也许是在执行errorMessageSearcher.resendErrorMsg(startTime,endTime);方法一直没退出。。
Thread-3的run方法:
public void run() { log.info("Thread Name="+Thread.currentThread().getName());//Hhread-3 while(true){ endTime = DateUtil.convertDateTOStr(new Date(), DateUtil.PALETTE_8); log.debug(Thread.currentThread().getName()+"查询定时发送的消息时间范围:"+startTime+"---->"+endTime); try { errorMessageSearcher.resendErrorMsg(startTime,endTime); } catch (IOException e1) { log.error(e1); } catch (ClientException e1) { log.error(e1); } try { Thread.sleep(100); } catch (InterruptedException e) { log.error(e); } } }
跟着这个思路,刚才仔细检查了errorMessageSearcher.resendErrorMsg(startTime,endTime)方法,见下方注释掉的方法,之前是通过Lucene搜索到到点可以重发的数据后,调用客户端代码,通过socket再向我Server发一条数据过来,而现在改成了直接将要重发的消息加入到接收消息的内存List中。
public int resendErrorMsg(String begin,String end) throws IOException, ClientException{ if(ErrorMessageIndexer.getInstance().isHasUpdated()==true){ ErrorMessageIndexer.getInstance().commit(); reader = IndexReader.openIfChanged(reader); searcher = new IndexSearcher(reader); } int rtnValue = 0; TermRangeQuery rangeQuery = new TermRangeQuery(ErrorMessageIndexer.NEXT_DATE_FIELD,begin, end,true,true); ; //获得得分靠前的max个匹配记录 ScoreDoc[] docs = searcher.search(rangeQuery,max).scoreDocs; if(docs!=null&&docs.length>0){ rtnValue = docs.length; for(int i = 0; i < docs.length; i++) { int docId = docs[i].doc; Document doc = searcher.doc(docId); String message = doc.get(ErrorMessageIndexer.ERROR_MESSAGE_FIELD); String uuid = doc.get(ErrorMessageIndexer.UUID_FIELD); //通过客户端,调用socket通信,将消息发送到infoList中去 // IIPayrelayClient client = new SyncIPayrelayClient(); // client.request(message, false); //直接加入到消息队列中 WSData wsData = new WSData(); wsData.setMessage(message); InfoReceiveThreadPoolManager.getInstance().addInfoQueue(wsData); //删除索引 log.debug("删除索引开始:"+uuid); ErrorMessageIndexer.getInstance().deleteWSData(uuid); log.debug("删除索引结束:"+uuid); } } return rtnValue; }
通过这样修改后,1000条数据重发4次都顺利完成了,完成后Thread-3又回到了休眠状态。
第三次测试
像上面那么改了之后,并发1000条是轻松的就处理完了,于是测试了一下1w条异常数据的情况,这下苦逼了。
pool2全部都堵塞了在等锁,不过pool1都空了。
这个也很好解释,上面java代码中的这句:
InfoReceiveThreadPoolManager.getInstance().addInfoQueue(wsData);
导致异常的消息不用再进入发送消息队列了,直接写如了接收队列,于是接收队线程池很紧张了,发送线程池则等待接收到的消息转到发送线程池中,暂时还表示无压力,过一会儿之后可以看到发送线程池开始绿了~
我的Server是用的QuickServer实现的。通过实现QSAdmin的方法,打印了当时的线程情况。
1032条在infoList中等待发送,7747条数据出错等待到点重发。活动的发送消息线程池中线程为0,活动的接收消息线程池中线程为100(也就是我设置的最大值)。
-----------------------------------------------------
今天一边写这个blog,一边解决我的问题了,遇到想起可以优化的再来完善,完全直播。
顺便摸索着学习了把怎么用visual vm分析问题。很多时候还是靠灵光一现就发现了漏洞,慢慢积累灵光就会越来越多~~
相关推荐
3. **线程分析**:Visual VM提供线程的详细视图,显示线程状态、阻塞原因以及死锁检测,帮助调试多线程问题。 4. **方法和类的性能分析**:可以追踪方法调用和类加载,了解哪些代码段执行时间较长,优化性能关键...
2. **CPU使用情况**:Visual VM可以帮助开发者追踪应用程序的CPU使用率,显示哪个线程或方法占用了最多的计算资源。这对于定位CPU瓶颈至关重要。在"CPU"视图中,你可以看到每个线程的调用堆栈,帮助定位导致高CPU...
Visual VM 提供了查看和分析线程状态的能力,包括线程的挂起、等待、阻塞等状态,这对于调试多线程问题非常有帮助。 3. **CPU性能分析**:通过CPU视图,开发者可以查看哪些方法消耗了最多的CPU时间,从而找出性能...
Visual VM是一款强大的Java性能分析工具,它集成了多种功能,如内存分析、线程分析、CPU剖析以及JVM垃圾收集(GC)监视。其中,GC插件是Visual VM的一个重要组成部分,用于深入理解Java应用程序的内存管理和垃圾收集...
Visual VM是一款强大的Java性能分析工具,它包含了丰富的功能,如CPU和内存监控、线程分析、JMX连接等。在Java开发和运维过程中,我们常常使用Visual VM来诊断和优化应用性能。而JConsole则是另一个Java性能监视工具...
- **线程CPU使用**:分析各个线程的CPU占用情况,帮助识别CPU密集型任务。 - **热点代码分析**:通过热点图展示哪些代码段消耗了最多的CPU资源。 通过上述内容的学习,我们可以看出VisualVM是一款非常实用且功能...
比如路径X:\ProgramFiles\MVTec\HALCON-10.0\bin\dotnet20下无法使用,而X:\ProgramFiles\MVTec\HALCON-10.0\bin\dotnet35下可以使用。这通常与.net框架版本不匹配有关。 - **控件无法显示图片**:如果在使用Halcon...
在提供的压缩包文件中,"远程线程注入.sln"是一个Visual Studio解决方案文件,很可能包含了实现上述步骤的源代码项目。"Debug"和".vs"目录通常包含编译过程中产生的中间文件和配置信息。"远程线程注入"可能是源代码...
它与JVisualVM(Java Visual VM)紧密集成,提供了图形化的界面,帮助用户直观地理解Java虚拟机(JVM)的内存管理和垃圾回收过程。在本文中,我们将深入探讨Visual GC插件在JDK 1.6.0_45版本中的实际应用和其核心...
JVisualVM是一款集成化工具,它包含了多种Java应用性能分析功能,如监视CPU使用率、内存状况、线程状态、类加载、垃圾收集等。JVisualVM不仅能够本地运行,还可以远程连接到其他正在运行的Java进程,为开发者提供了...
本教程将深入探讨如何使用C++ .NET语言在Visual Studio .NET环境下编写程序来实现这一功能。 首先,我们需要了解Windows API提供的相关函数。在Windows操作系统中,我们可以调用`CreateToolhelp32Snapshot`、`...
4. **性能优化**:虚拟环境下可能会影响系统性能,合理调整虚拟机的CPU和内存资源分配,以及使用合适的虚拟化技术,如VT-x或AMD-V,有助于提升运行效率。 5. **安全性考虑**:由于虚拟机与主机共享资源,必须注意...
它允许开发者深入了解JVM(Java虚拟机)的内部工作,包括内存使用、CPU消耗、线程状态以及方法调用等信息。VisualVM提供了丰富的可视化界面,使得开发者能够方便地监控和诊断Java应用程序的性能问题。 标题中的...
`OpenProcess`函数用于获取对目标进程的访问权限,参数如`PROCESS_CREATE_THREAD`, `PROCESS_VM_OPERATION`, 和 `PROCESS_VM_WRITE`分别允许创建线程、执行虚拟内存操作和写入虚拟内存。如果没有足够的权限,就需要...
这些工具与 JDK 的标准版本是一致的,可以使用 VisualVM 生成和分析海量数据、跟踪内存泄漏、监控垃圾回收器、执行内存和 CPU 分析。 如何获取 VisualVM VisualVM 是一个免费的工具,可以从官方网站下载。下载完成...
它集成了多种功能,包括内存分析、线程检查、CPU使用率监控、类加载和垃圾回收查看等,能够帮助开发者深入理解Java应用程序的运行状态。 标题中的"visualvm中文版"指的是该工具提供了中文界面,使得中国用户在使用...
2. 在"配置属性"中,选择"多线程DLL",并确保使用与Java相同的编译器版本,这里是VC9.0。 3. 编写JNI函数,遵循JNI头文件(如`jni.h`)定义的规范。这些函数需要与Java中的方法签名匹配。 在Netbeans中配置JNI项目...