ExecutorService修复线程拒绝

时间:2014-04-28 15:51:34

标签: java multithreading java-ee threadpool executorservice

我遇到一些线程问题。

我的剧本

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 ....
    }
}

谢谢。

2 个答案:

答案 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