原本想给 多线程任务 做一个挂起(暂停)功能,然后配合 httpcomponents-asyncclient 并发测试,结果意外令人汗颜,竟然CPU占用100%。。。
使用VisualVM观察CPU抽样,发现org.apache.http.impl.nio.reactor.AbstractIOReactor.execute()方法总是占用大部分CPU,然而没调用挂起操作时却一切正常。
这挂起操作的其中一环需要中断线程,这些线程均出产自自定义ThreadFactory:
public class GroupThreadFactory implements ThreadFactory {
private final ThreadGroup group;
private final AtomicInteger threadNumber;
public GroupThreadFactory() {
this.group = new ThreadGroup("WorkerGroup");
this.threadNumber = new AtomicInteger(1);
}
public Thread newThread(Runnable r) {
Thread t = new Thread(null, r, "pool-thread-" + threadNumber.getAndIncrement(), 0);
if (t.isDaemon())
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
public ThreadGroup getGroup() {
return this.group;
}
}
ThreadGroup能做到中断从属于此线程组的所有线程。
难道asyncclient的内部线程跑到这ThreadGroup里了,然后被中断后导致无限循环?
故意用Eclipse搜索“ThreadFactory”引用关系,果真发现asyncclient实现的ThreadFactory:
// org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor
static class DefaultThreadFactory implements ThreadFactory {
private static volatile int COUNT = 0;
public Thread newThread(final Runnable r) {
return new Thread(r, "I/O dispatcher " + (++COUNT));
}
}
这就费解了……有扯到啥ThreadGroup吗?
回归Thread源码,发现初始化方法:
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
Thread parent = currentThread();
SecurityManager security = System.getSecurityManager();
if (g == null) {
/* Determine if it's an applet or not */
/* If there is a security manager, ask the security manager
what to do. */
if (security != null) {
g = security.getThreadGroup();
}
/* If the security doesn't have a strong opinion of the matter
use the parent thread group. */
if (g == null) {
g = parent.getThreadGroup();
}
}
其中“ g = parent.getThreadGroup(); ”表明最低情况下会采用当前线程的线程组,实际上几乎采用这种方式。
这就解释了为什么内置的ThreadGroup会跑到asyncclient里去了!
尝试过分析修改Thread与ThreadGroup的引用关系,结果无奈放弃,毕竟是Java重要API,哪会随便让人修改。
最后,我从run方法下手。
/**
* Give up {@link ThreadGroup}
* @author Adan
*/
public abstract class InterruptableThreadFactory implements ThreadFactory {
private final String name;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private InterruptableThreadFactory(String factoryName){
this.name = factoryName + "-thread-";
}
private abstract class IThread extends Thread{
public IThread(ThreadGroup group, Runnable target, String name, long stackSize) {
super(group, target, name, stackSize);
}
protected abstract void started();
@Override public final void run() {
if(Thread.currentThread() == this){ // the RUNNING thread only
this.started(); // code here would be safe absolutely
try {
super.run();
} finally {
this.terminated();
}
}else{
super.run();
}
}
/**
* invoked by the RUNNING thread
*/
protected abstract void terminated();
}
public final Thread newThread(Runnable r) {
Thread t = new IThread(null, r, this.name+threadNumber.getAndIncrement(), 0) {
@Override protected void started() {
hold(this);
}
@Override protected void terminated() {
releaseThread();
}
};
if (t.isDaemon())
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
/**
* 释放当前线程在此占用的资源。
*/
final void releaseThread() {
this.release(Thread.currentThread());
}
abstract void release(Thread t) ; // 注意挂起线程时与释放资源时的锁等待冲突
abstract void hold(Thread t) ;
public abstract Object[] snapshotThreads() ; // copy on read
abstract int threadSize() ;
/**
* 中断所有持有线程。<br/>
* @see #doInterrupt(Object[])
* @see #doInterrupt(Iterator)
*/
public void interruptThreads() {
this.doInterrupt( this.snapshotThreads() );
}
final void doInterrupt(Object[] threads) {
for (int i = 0; i < threads.length; i++) {
this.interrupt( (Thread) threads[i] );
}
}
/**
* @param threadIterator 弱一致的
*/
final void doInterrupt(Iterator<Thread> threadIterator) { // interruptDirectThreads
while ( threadIterator.hasNext() ) {
this.interrupt( threadIterator.next() );
}
}
private final void interrupt(Thread t) {
if (t.getState() != Thread.State.TERMINATED) t.interrupt();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(50);
sb.append("InterruptableThreadFactory@").append(Integer.toHexString(super.hashCode()))
.append("(threadSize=").append(this.threadSize()).append(')');
return sb.toString();
}
public static InterruptableThreadFactory newInstance(String factoryName, boolean large){
if(large){
return new InterruptableThreadFactory(factoryName){
...
};
}else{
return new InterruptableThreadFactory(factoryName){
@SuppressWarnings("serial")
private final Collection<Thread> threadSet = new java.util.ArrayList<Thread>(){ @Override public synchronized final boolean remove(Object o){return super.remove(o);}
@Override public synchronized final boolean add(Thread e){return super.add(e);}
@Override public synchronized final Object[] toArray(){return super.toArray();}
@Override public synchronized final int size() { return super.size(); }
};
@Override final void release(Thread t) {
this.threadSet.remove(t);
}
@Override final void hold(Thread t) {
this.threadSet.add(t);
}
@Override public final Object[] snapshotThreads() {
Object[] threads = this.threadSet.toArray();
return threads;
}
@Override final int threadSize() {
return this.threadSet.size();
}
};
}
}
}
OK,测试通过。
不过话说回来,感觉“组”概念被削弱,成了鸡肋。
来源:oschina
链接:https://my.oschina.net/u/1017097/blog/158446