我正在开发应用程序( Matt的traceroute windows版本http://winmtr.net/),它创建了多个线程,每个线程都有自己的进程(执行ping命令)。 ThreadPoolExecutor
在一段时间后(例如10秒)关闭所有线程
ThreadPoolExecutor
使用阻塞队列(在执行任务之前保留任务)
int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(
NUMBER_OF_CORES * 2, NUMBER_OF_CORES * 2 + 2, 10L, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>()
);
PingThread.java
private class PingThread extends Thread {
@Override
public void run() {
long pingStartedAt = System.currentTimeMillis();
// PingRequest is custom object
PingRequest request = buildPingRequest(params);
if (!isCancelled() && !Thread.currentThread().isInterrupted()) {
// PingResponse is custom object
// Note:
// executePingRequest uses PingRequest to create a command
// which than create a runtime process to execute ping command
// using string response i am creating PingResponse
PingResponse pingResponse = PingUtils.executePingRequest(request);
if (pingResponse != null) {
pingResponse.setHopLocation(hopLocation);
// publish ping response to main GUI/handler
publishProgress(pingResponse);
} else
Logger.error(
"PingThread", "PingResponse isNull for " + request.toString()
);
}
}
}
现在,如果我在循环中创建多个线程超过500并在池执行器内执行
执行主题
PingThread thread = new PingThread(params);
poolExecutor.execute(thread);
我知道LinkedBlockingQueue
在执行任务之前会先执行任务。每个线程的进程最多需要200到400毫秒,但通常小于10毫秒
我在做什么
for (int iteration = 1; iteration <= 50/*configurable*/; iteration++) {
for (int index = 0; index < 10/*configurable*/; index++) {
PingThread thread = new PingThread(someParams);
poolExecutor.execute(thread);
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Logger.error(false, e);
}
}
50次迭代将需要大约25秒,在这里我只有最多40个ping响应,其余因为超时而被视为损失。如果我增加迭代损失也会增加(由于线程数没有增加而呈指数增长)
观察:
我在Galaxy S6上运行此应用程序,它有8个内核,应用程序池大小为16,最大池大小为16 + 2,我知道处理器一次只运行一个线程,它共享一个量子时间并行处理
通过及时观察ThreadPoolExecutor
,我看到许多任务在队列中,超时后,由于LinkedBlockingQueue
如果我减少了没有线程,它可以正常工作,但如果增加则会产生问题
问题:
ConcurrentLinkedQueue
但是它使用生产者/消费者模型,不知怎的ThreadPoolExecutor
(我认为是)也使用这个模型。LinkedBlockingQueue
在执行任务之前保存任务(线程空闲或在队列中),如何克服这个问题?Thread.MAX_PRIORITY
不能解决问题(后来的迭代&#39; s线程在队列中)corePoolSize
在我的情况下不起作用。测试期间,内存和处理器的使用情况有限制。
需要详细解答/帮助。
修改
当应用程序进入后台时,没有丢失,用户CPU使用率下降到0-2%,而焦点应用程序占用了4-6%的CPU使用率。是因为UI和其他ralted东西,我试图删除所有不必要的代码,我也改变了PingThread
到PingTask
PingTask implements Runnable {/*....*/}
注意: 我使用相同的代码创建了单独的基于java的应用程序,它在桌面上运行良好,所以我们可以说它的Android操作系统特定问题吗?
答案 0 :(得分:5)
我不确定这是否是导致所有问题的原因,但是您正在创建一个很多的不必要的线程。
你应该替换
[{"group_id":87,"group_name":"\u06af\u0632\u06cc\u0646\u0647 \u0647\u0627\u06cc \u0639\u0645\u0648\u0645\u06cc","group_slug":"%da%af%d8%b2%db%8c%d9%86%d9%87-%d9%87%d8%a7%db%8c-%d8%b9%d9%85%d9%88%d9%85%db%8c","group_desc":"","attributes":[{"attr_id":95,"attr_name":"\u062a\u0627\u0631\u06cc\u062e \u0627\u0646\u062a\u0634\u0627\u0631","attr_slug":"%d8%aa%d8%a7%d8%b1%db%8c%d8%ae-%d8%a7%d9%86%d8%aa%d8%b4%d8%a7%d8%b1","attr_desc":"","value":"144"},{"attr_id":96,"attr_name":"\u0648\u0636\u0639\u06cc\u062a \u0628\u0627\u0632\u0627\u0631","attr_slug":"stock","attr_desc":"","value":"instock"},{"attr_id":99,"attr_name":"\u0628\u0644\u0648\u062a\u0648\u062b","attr_slug":"%d8%a8%d9%84%d9%88%d8%aa%d9%88%d8%ab","attr_desc":"","value":"yes"},{"attr_id":100,"attr_name":"\u0648\u0627\u06cc \u0641\u0627\u06cc","attr_slug":"%d9%88%d8%a7%db%8c-%d9%81%d8%a7%db%8c","attr_desc":"","value":"no"}]},{"group_id":89,"group_name":"\u0635\u0641\u062d\u0647 \u0646\u0645\u0627\u06cc\u0634","group_slug":"%d8%b5%d9%81%d8%ad%d9%87-%d9%86%d9%85%d8%a7%db%8c%d8%b4","group_desc":"","attributes":[]},{"group_id":57,"group_name":"\u067e\u0631\u062f\u0627\u0632\u0646\u062f\u0647","group_slug":"%d9%be%d8%b1%d8%af%d8%a7%d8%b2%d9%86%d8%af%d9%87","group_desc":"","attributes":[]}]
with:
private class PingThread extends Thread {
或(使用更合适的名称):
private class PingThread implements Runnable {
即。提交给private class PingTask implements Runnable {
的任务不应该是自己的线程。它有效,因为Executor
实现了Thread
,但是你在浪费它。
答案 1 :(得分:3)
线程创建一个新的唯一对象,而runnable允许所有线程共享一个对象。因此,在尝试多线程时不应扩展Thread,而应使用Runnable:
class RunnableDemo implements Runnable {
private Thread thread;
String threadName="My thread";
public void run() {
//do your code from here 'logic'
System.out.println("Threading is Running");
try {
for(int i = 4; i > 0; i--) {
System.out.println("Thread: "+threadName +" "+ i);
// Let the thread sleep for a while.
Thread.sleep(50); //sleep your content for xx miliseconds
}
} catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread " + threadName + " exiting.");
//finish your work here
}
public void start () {
System.out.println("Starting " + threadName );
if (thread == null) {
thread = new Thread (this);
thread.start (); //This will call your run methods of Runnable
}
}
}
//test your thread from here
public class TestThread {
public static void main(String args[]) {
RunnableDemo R1 = new RunnableDemo( "Thread-1");
R1.start();
RunnableDemo R2 = new RunnableDemo( "Thread-2");
R2.start();
}
}
答案 2 :(得分:3)
使用相同的代码创建和观察独立的java应用程序(日志)后,我开始了解以下内容:
LinkedBlockingQueue
在执行任务之前保存任务,因此如果我们有一个长队列,队列中的线程将不得不等待更多。corePoolSize
和maxPoolSize
也是这样,他们在队列中添加了线程对于50次迭代和10次内部创建500个线程,我现在做了两件事:
Thread.sleep(millis)
时间。Math.ceil((double) 10 / 3) = 3
,因此每个线程有3个连续PingUtils.executePingRequest(pingRequest)
,即3 * 3 = 9
保持为1,因此我们将为最后一个请求创建一个单独的线程。对于每次迭代而不是现在创建10个线程,我创建了4个线程。