我遇到一些线程问题。
我的剧本
1 - 从文本文件
中加载超过1000万行到Array
2 - 创建ExecutorPool
5 固定线程
3 - 然后它正在迭代该列表并将一些线程添加到队列
executor.submit(new MyCustomThread(line,threadTimeout,"[THREAD "+Integer.toString(increment)+"]"));
现在活动线程永远不会绕过5个固定线程,这很好,但我发现我的处理器进入100%负载,我已经调整了一点点,我看到正在调用MyCustomThread
构造函数,巫婆意味着无论我是否声明5个固定线程,ExecutorService
仍然会尝试创建10个数百万个对象。
主要问题是: 我该如何防止这种情况?我只想让线程被拒绝,如果它们没有空间,不要创建1000万个对象并逐个运行它们。
第二个问题:
我如何获得当前活动线程?我试过threadGroup.activeCount()
,但总是给我5 5 5 5 ....
CALLER CLASS:
System.out.println("Starting threads ...");
final ThreadGroup threadGroup = new ThreadGroup("workers");
//ExecutorService executor = Executors.newFixedThreadPool(howManyThreads);
ExecutorService executor = Executors.newFixedThreadPool(5,new ThreadFactory() {
public Thread newThread(Runnable r) {
return new Thread(threadGroup, r);
}
});
int increment = 0;
for(String line : arrayOfLines)
{
if(increment > 10000)
{
//System.out.println("TOO MANY!!");
//System.exit(0);
}
System.out.println(line);
System.out.println(threadGroup.activeCount());
if(threadGroup.activeCount() >= 5)
{
for(int i = 0; i < 10; i++)
{
System.out.println(threadGroup.activeCount());
System.out.println(threadGroup.activeGroupCount());
Thread.sleep(1000);
}
}
try
{
executor.submit(new MyCustomThread(line,threadTimeout,"[THREAD "+Integer.toString(increment)+"]"));
}
catch(Exception ex)
{
continue;
//System.exit(0);
}
increment++;
}
executor.awaitTermination(10, TimeUnit.MILLISECONDS);
executor.shutdown();
线程类:
public class MyCustomThread extends Thread
{
private String ip;
private String threadName;
private int threadTimeout = 10;
public MyCustomThread(String ip)
{
this.ip = ip;
}
public MyCustomThread(String ip,int threadTimeout,String threadName)
{
this.ip = ip;
this.threadTimeout = threadTimeout;
this.threadName = threadName;
System.out.prinln("MyCustomThread constructor has been called!");
}
@Override
public void run()
{
// do some stuff that takes time ....
}
}
谢谢。
答案 0 :(得分:2)
你这样做有点不对劲。执行者的理念是将工作单元实现为Runnable或Callable(而不是Thread)。每个Runnable或Callable应该做一个原子工作,它与其他Runnables或Callables互斥。
Executor服务在内部使用一个线程池,所以你创建一个线程组和Thread没有任何好处。
试试这个简单的部分:
ExecutorService executor = Executors.newFixedThreadPool(5);`
executor.execute(new MyRunnableWorker());
public class MyRunnableWorker implements Runnable{
private String ip;
private String threadName;
private int threadTimeout = 10;
public MyRunnableWorker(String ip){
this.ip = ip;
}
public MyRunnableWorker(String ip,int threadTimeout,String threadName){
this.ip = ip;
this.threadTimeout = threadTimeout;
this.threadName = threadName;
System.out.prinln("MyRunnableWorker constructor has been called!");
}
@Override
public void run(){ {
// do some stuff that takes time ....
}
}
这会给你你想要的东西。还尝试使用visualVM测试线程代码执行,以查看线程如何运行以及负载分布。
答案 1 :(得分:1)
我认为您最大的问题是MyCustomThread
应该实现Runnable
,而不是Thread
。当您使用ExecutorService
时,您可以让它处理Thread
管理(即您不需要创建它们。)
这是我认为您尝试做的事情的近似值。希望这会有所帮助。
public class FileProcessor
{
public static void main(String[] args)
{
List<String> lines = readFile();
System.out.println("Starting threads ...");
ExecutorService executor = Executors.newFixedThreadPool(5);
for(String line : lines)
{
try
{
executor.submit(new MyCustomThread(line));
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
try
{
executor.shutdown();
executor.awaitTermination(10, TimeUnit.SECONDS);
}
catch (InterruptedException e)
{
System.out.println("A processor took longer than the await time to complete.");
}
executor.shutdownNow();
}
protected static List<String> readFile()
{
List<String> lines = new ArrayList<String>();
try
{
String filename = "/temp/data.dat";
FileReader fileReader = new FileReader(filename );
BufferedReader bufferedReader = new BufferedReader(fileReader);
String line = null;
while ((line = bufferedReader.readLine()) != null) {
lines.add(line);
}
bufferedReader.close();
}
catch (Exception e)
{
e.printStackTrace();
}
return lines;
}
}
public class MyCustomThread implements Runnable
{
String line;
MyCustomThread(String line)
{
this.line = line;
}
@Override
public void run()
{
System.out.println(Thread.currentThread().getName() + " processed line:" + line);
}
}
编辑: 此实现不会阻止ExecutorService提交。我的意思是,无论先前提交的MyCustomThreads是否已完成,都会为文件中的每一行创建一个新的MyCustomThread实例。您可以添加阻止/限制工作队列以防止这种情况。
ExecutorService executor = new ThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS, new LimitedQueue<Runnable>(10));
可以找到阻止/限制队列实现的示例here: