在哪里使用线程中断

时间:2015-02-26 15:27:36

标签: java multithreading threadpool

我有一些我正在使用的旧代码,而且我对Threads没有太多经验(主要是在前端工作)。无论如何,这个Thread.sleep导致线程挂起,我不确定该怎么做。我想过使用一个计数器并抛出一个Thread.currentThread.interupt,但不确定它放在哪里或它会插入哪个线程。这是转储的一个例子。正如您所看到的,线程数在1708处变得非常高。

有什么建议吗?

  

"螺纹-1708" prio = 6 tid = 0x2ceec400 nid = 0x2018等待条件   [0x36cdf000] java.lang.Thread.State:TIMED_WAITING(sleep)at   java.lang.Thread.sleep(Native Method)锁定的可拥有同步器:      - 无" Thread-1707" prio = 6 tid = 0x2d16b800 nid = 0x215c等待条件[0x36c8f000] java.lang.Thread.State:TIMED_WAITING   (sleep)at java.lang.Thread.sleep(Native Method)Locked ownable   同步:      - 没有

@Override
public void run()
{
    Connection con = null;
    int i = 0;

    while (is_running)
    {
        try
        {
            con = ConnectionManager.getConnection();

            while (!stack.isEmpty())
            {
                COUNT++;
                String line = (String) stack.pop();
                getPartMfr(line);
                try
                {
                    if (this.mfr != null && !this.mfr.equals(EMPTY_STR))
                    {
                        lookupPart(con, line);
                    }
                }
                catch (SQLException e)
                {
                    e.printStackTrace();
                }
                if (COUNT % 1000 == 0)
                {
                    Log log = LogFactory.getLog(this.getClass());
                    log.info("Processing Count: " + COUNT);
                }
            }
        }
        catch (NamingException e)
        {
            e.printStackTrace();
        }
        catch (SQLException e)
        {
            e.printStackTrace();
        }
        finally
        {
            try
            {
                ConnectionManager.close(con);
            }
            catch (SQLException e)
            {
                e.printStackTrace();
            }
        }


        try {
            Thread.sleep(80);

        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
    this.finished = true;

}

这里是调用run方法的地方,因为你可以看到它确实将它设置为false,但我猜它缺少线程?

    HarrisWorker w[] = new HarrisWorker[WORKER_POOL_SIZE];
    try
    {
        for (int i = 0; i < w.length; i++)
        {
            w[i] = new HarrisWorker(pw);
            w[i].start();
        }
        pw.println(headers());
        File inputDir = new File(HARRIS_BASE);
        String files[] = inputDir.list();
        for (String file : files)
        {

            try
            {
                File f = new File(HARRIS_BASE + File.separator + file);
                if (f.isDirectory())
                    continue;
                final String workFile = workDir + File.separator + file;
                f.renameTo(new File(workFile));

                FileReader fr = new FileReader(workFile);
                BufferedReader br = new BufferedReader(fr);
                String line = br.readLine();

                boolean firstLine = true;

                while (line != null)
                {
                    if (firstLine)
                    {
                        firstLine = false;
                        line = br.readLine();
                        continue;
                    }
                    if (line.startsWith(","))
                    {
                        line = br.readLine();
                        continue;
                    }
                    //          if(line.indexOf("103327-1") == -1)
                    //          {
                    //              line = br.readLine();
                    //              continue;
                    //          }
                    HarrisWorker.stack.push(line);
                    line = br.readLine();
                }
                br.close();
                fr.close();
                for (int i = 0; i < w.length; i++)
                {
                    w[i].is_running = false;

                    while (!w[i].finished)
                    {

                        Thread.sleep(80);   
                    }

                }
                move2Processed(file, workFile);
                long etime = System.currentTimeMillis();
                System.out.println("UNIQUE PARTS TOTAL FOUND: " + HarrisWorker.getFoundCount() + " of " + HarrisWorker.getUniqueCount() + ", "
                        + (HarrisWorker.getFoundCount() / HarrisWorker.getUniqueCount()));
                System.out.println("Time: " + (etime - time));


            }
            catch (Exception e)
            {
                e.printStackTrace();
                File f = new File(workDir + File.separator + file);
                if (f.exists())
                {
                    f.renameTo(new File(HARRIS_BASE + File.separator + ERROR + File.separator + file));
                }

            }
        }
    }

2 个答案:

答案 0 :(得分:2)

直接回答你头衔中的问题 - 无处可去。此代码中没有任何地方需要Thread.interrupt()

线程名称为Thread-1708的事实并不一定意味着有1708个线程。可以为线程选择任意名称。我通常在线程名称中包含执行程序或服务的名称。也许1600现在已经停止了,只有大约一百个活着。也许这个特殊的类在1700开始命名以区别于其他用途。

1708个线程可能不是问题。如果你有一个并行服务2000个连接的多线程服务器,那么当然可以预期有2000个线程在做这个,还有一堆其他线程。

你必须理解为什么sleep存在,它的用途是什么。它不存在只是为了什么都没有记忆。

将代码翻译成&#34;明文&#34; (顺便说一下,使用try-with-resources获取和关闭连接可以大大简化它:)

  • 获取连接
  • 使用连接发送(我猜)堆栈中的任何内容
  • 失败或完成时 - 等待80毫秒(这是您的sleep
  • 如果仍设置run标志 - 从步骤1开始重复
  • 完成主题。

现在仔细阅读,显而易见它不是问题的sleep。它是run标志未设置为false。而且你的线程只是继续循环,即使它根本无法获得连接 - 它只会花费大部分时间等待重试。实际上 - 即使你完全剥离sleep(而不是在中途中断),你所能实现的只是Threads将开始耗尽更多资源。鉴于你有一个记录器,你可以通过stdout打印到printStackTrace,我会说你有2个问题:

  • 某些事情正在产生线程,之后没有停止它们(完成后没有将run标记设置为false
  • 获取Connection时可能会遇到异常,但您从未在日志中看到它们。

可能是Thread应该设置它自己的run标志(比如当堆栈被耗尽时),但你必须自己决定 - 这取决于很多细节

答案 1 :(得分:1)

如果您正在为实时生产系统编写代码,那么您应该知道一些答案:

: - (变量和方法都有相同的名称,run。变量的更好名称可能是keep_running或者,改变它的意义,以便你可以写while (! time_to_shut_down) { ... }

: - ( Thread.sleep(80)这是为了什么?对我来说这看起来像是一个大红旗。你永远无法通过添加sleep()来调解并发错误你所能做的就是让bug在测试中不太可能发生。这意味着,当bug最终 咬人时,它会让你在生产系统中咬人。

: - (您的run()方法方式过于复杂(关键字try出现了四次)。请将其分解。

: - (忽略五个不同的异常catch (MumbleFoobarException e) { e.printStackTrace(); }大多数异常(但可能不是InterruptedException)意味着出现了错误。您的程序应该< em>做不仅仅是向标准输出写一条消息。

: - ()将错误消息写入标准输出。您应该调用log.error(...),以便您的应用程序可以配置为将消息发送到某人可能实际看到的地方他们。