用户创建的线程池关闭在添加sysout时具有不同的行为

时间:2014-11-18 07:23:41

标签: java multithreading

我被要求在面试中创建自己的线程池,我必须创建用户请求的线程数。允许用户提交任务并最终关闭池。我编写了下面的程序,除了关闭以外的所有情况都能正常工作。

public class ThreadPool
{ 
public final Queue<Runnable> workerQueue;
private static boolean isrunning = true;
private Thread[] workerThreads;


public ThreadPool(int N)
{
    workerQueue = new LinkedList<>();
    workerThreads = new Thread[N];
    for (int i = 0; i < N; i++) {
        workerThreads[i] = new Worker("Pool Thread " + i);
        workerThreads[i].start();
    }
}

public void shutdown()
{
    while(isrunning){
        if(workerQueue.isEmpty()){

            isrunning = false;
        }
    }
}

public void  submit(Runnable r) throws Exception
{
        workerQueue.add(r);
}

private class Worker extends Thread
{
    public Worker(String name)
    {
        super(name);
    }

    public void run()
    {
        while (isrunning) {
            try {
                if(!workerQueue.isEmpty())
                {
                    Runnable r = workerQueue.poll();
                    r.run();
                }

            } catch (RuntimeException e) {
                e.printStackTrace();
            }
        }
    }
}

}

我写的测试方法如下

static public void main(String[] args) throws Exception
{

    ClassA a1 = new ClassA();
    ClassA a2 = new ClassA();
    ClassA a3 = new ClassA();
    ClassA a4 = new ClassA();
    ClassA a5 = new ClassA();
    ClassA a6 = new ClassA();

    ThreadPool tp = new ThreadPool(5);

    tp.submit(a1);
    tp.submit(a2);
    tp.submit(a3);
    tp.submit(a4);
    tp.submit(a5);
    ///////////////
    tp.submit(a6);
    tp.shutdown();

}

但程序永远不会结束,它总是在运行,我必须在eclipse中手动停止它。但是如果我在方法关闭时添加一个简单的System.out.print(&#34;&#34;),它就会正常工作(程序在所有线程执行后结束)。

你能告诉我为什么它与sysout一起工作以及它为什么不使用它?

1 个答案:

答案 0 :(得分:0)

您的代码存在两个主要问题:

  1. 您正在使用在多线程环境中未同步的Queue实现。当多个线程从队列中插入/删除时,这会导致Race Condition。请考虑使用以下内容:

    workerQueue = new ConcurrentLinkedQueue()

  2. 你运行了一些非常紧凑的循环,一个是Worker.run()方法中的一个,你不会检查NPE而不允许某些&#34;冷却&#34;和另一个循环shutdown()

    while (isrunning) { ... Runnable r = workerQueue.poll(); r.run(); ... }

    这与1一起导致Queue被清空而没有正确更新尺寸信息:即。 isEmpty()返回falsepoll()返回null。你的程序将陷入循环。由于特定于您的配置的不同时序而添加System.out.print()时,这种情况不会发生(在其他环境中可能会继续失败 - 特别是在可用的cpu核心数超过6的情况下)。

    < / LI>