[讨论] 请教一下如何控制JVM中的线程
michael9527
2012-02-03
我需要在运行时,获取到正在运行的所有线程,JVM自身的那些线程不需要。
然后对这些线程进行一些操作,比如暂停,休眠等。 通过JMX可以拿到所有线程,但是无法对这些线程进行休眠,等待操作,Thread类里面那些wait(),sleep()方法都是针对当前线程的。就算我拿到其他线程的引用还是无法操作他们。请问有什么好的办法呢? |
|
RednaxelaFX
2012-02-03
如果你在想做这种事情,你多半在尝试做你不应该从Java程序做的事。
但,如果你非要做的话,当然不是没办法。Thread上有suspend()和resume()方法,虽然已经是deprecated,但还存在,也还可以调用,只是不保证安全。原本这两个方法被deprecate就是因为它们的使用方式有潜在死锁的可能。 拿到所有线程之后,对你要暂停的线程调用suspend()就可以把它们停下来;回头对它们调用resume()就能恢复它们的执行。注意别把自己(当前线程)给suspend()了,你总得留个活口。 再提醒一次,虽然你可以写出代码做这件事情,但这样做就是给自己挖坑;一旦依赖上这俩方法,回头出现诡异的问题修起来就麻烦了。 |
|
michael9527
2012-02-03
呵呵,当时看了API就没敢用,万一出现死锁了就惨了。
您说的“半在尝试做你不应该从Java程序做的事” 意思是这种事情只有用C才能做到吗? 昨天我看了一下JPDA方面的介绍,似乎用底层一点的C可以做到,不过我已经不会C了 除了这两个被deprecate的方法之外,还有其他办法吗? |
|
RednaxelaFX
2012-02-03
不是说C能做而Java不能,是你已经在用Java这种相对高层的语言,原则上应该少做危险的操作。
除了suspend()/resume(),没有别的现成的办法从Java代码控制所有Java线程的运行状态。 =============================== 有一种很猥琐的办法,就是写个agent(JVMTI agent或者java.lang.instrument agent都行),拦截类加载,在类被真的加载之前改写里面的字节码, 1、找到所有循环末尾和方法结束(主要是正常返回,视情况看抛异常的地方是否也要包括) 2、在这些位置插入一些代码,检测一些你自己定义的条件,并在条件指定这个线程要暂停时自己调用wait() 3、另外写个类包装着这些条件。当需要恢复线程的执行时notify()它们。 这种办法必然会影响执行效率,不过至少可以纯Java实现,而且不会像suspend()/resume()那样不安全。 =============================== 其实问题的关键点是,你原本的目的是什么。或许要达到你的目的并不需要控制所有线程暂停啊啥的。 |
|
michael9527
2012-02-03
我的目的是在一个后台线程中检查某一个时间段整个JVM进程的CPU占用率,如果CPU占用率比较高,比如超过了60%或者70%,就将web容器中的一些线程给“暂停”,不是暂停所有的线程,只暂停线程池里面的线程,也就是跑着应用的那些线程,然后“暂停”个10分钟再恢复他们。
|
|
RednaxelaFX
2012-02-03
我知道你想做的是什么了。其实之前我这边也收到过类似的需求。
例如说有一个需求是,要Java线程支持透明的超时功能,一旦该线程执行时间超过一个阈值就把该线程杀掉,无论该Java线程在执行什么。需求的重点是应用代码不需要为这种超时功能改变自己的代码。 假如有多个“应用”要在同一个JVM里跑,而且想要做所谓的“应用隔离”,也就是一个应用的毛病不要影响到另一个应用,那么像这样的需要还是有合理性的。 可惜,我没做出来。要检查超时挺容易的,但最终该如何安全的杀掉一个Java线程?用Thread.stop()也不安全。不知道有啥好办法呢…有大牛给支几招就好了 |
|
michael9527
2012-02-03
RednaxelaFX谦虚了,您就是大牛。
我们的应用不是单个JVM,而是多个JVM,每个JVM跑一个应用。一台物理机器上会有多个JVM同时在跑。但如果某个JVM上的应用CPU占用率过高,此时应该做一些限制,目前的想法没说要杀掉,就是休眠,暂停一下 然后过一段时间恢复。 相比一个JVM里面跑多个应用的情况,这种一个JVM对应一个应用应该好做一些。不过连RednaxelaFX大侠也没做出啦,看来我是没办法了,实在不行就用最笨最简单的方式,把这个应用的JVM杀掉,过几分钟再启动。 |
|
RednaxelaFX
2012-02-03
杀JVM的话容易做,不过就是你得确保你的程序不会在执行过程中向外界泄漏脏数据。例如说不会向数据库写了后头还要修改的临时数据,之类的。
其实之前我也是建议这边的某个东西改为用多个JVM的,让进程做自然隔离。可是那边不干,我也没辙 |
|
michael9527
2012-02-03
RednaxelaFX如果按您说的用java.lang.instrument agent去实现的话,如果某个线程已经处于死循环中了,怎么办呢?
比如A线程 执行了一个while(true){},这时主线程可以对他进行suspend(),stop()等,但是都有风险,相对比较安全的是让他自己执行sleep和wait。可此时这个线程自己是没办法sleep或者wait了。那么即便我改了字节码也没用,在方法开头,结尾,或者新加一个方法。都不管用了,A线程根本不会执行到那段代码了。 这个问题还真不好办啊 |
|
RednaxelaFX
2012-02-03
michael9527 写道 RednaxelaFX如果按您说的用java.lang.instrument agent去实现的话,如果某个线程已经处于死循环中了,怎么办呢?
我不是说了要在循环末尾和方法结束的地方插入检查么。死循环再怎么死也要从后向前跳转才能形成循环。所以我说的检查是可以覆盖这种情况的。 while (true) { } 经过instrument后会变成 while (true) { if (MyCondition.shouldStopThisThread(Thread.currentThread())) { Thread.currentThread().wait(); } } 实际上就是照抄HotSpot VM所选择的safepoint的安插位置而已。 |
相关讨论
相关资源推荐
- HTML中实现鼠标经停时整行(tr)变色
- element表格 el-table双击单元格修改数据 鼠标离开焦点提交参数确定
- el-table高亮某一行, el-table给某一行设置特殊的样式
- element-ui+vue项目——实现表格table中的第一行中的输入框自动聚焦——基础积累
- vue中v-table某一列或者几列可编辑
- java鼠标离开编辑表格触发事件_JTable 失去焦点时取消编辑状态
- 鼠标点击表格,得到在table第几行第几列
- html5table双击事件,html的table实现双击打开编辑框,失去焦点保存
- element-table表格实现点击可编辑,失去焦点自动保存编辑的信息
- Vue实现Table内使用keyup移动单元格焦点