Java代码似乎只使用两个并发线程

时间:2012-07-18 04:01:41

标签: java concurrency

我有大约40000个可能需要重新绘制的对象。 他们中的大多数不在屏幕上,所以似乎我可以通过同时进行检查来节省大量工作。但是,我的CPU使用率从未超过15%,因此它似乎仍然只使用一个核心。我是否正确实现了线程?如果是这样,为什么不使用我的所有核心?是否有更好的方法可以利用我的所有内核?

public void paintComponent(Graphics g)
{
    super.paintComponent(g);

    if (game.movables.size() > 10000)
    {
        final int size = game.drawables.size();
        final Graphics gg = g;
        Thread[] threads = new Thread[8];
        for (int j = 0; j < 8; ++j)
        {
            final int n = j;
            threads[j] = new Thread(new Runnable()
            {
                public void run()
                {
                    Drawable drawMe;
                    int start = (size / 8) * n;
                    int end = (size / 8) * (n + 1);
                    if (n == 8) end = game.drawables.size(); // incase size
                                                             // % 8 != 0
                    for (int i = start; i < end; ++i)
                    {
                        drawMe = game.drawables.get(i);
                        if (drawMe.isOnScreen())
                        {
                            synchronized (gg)
                            {
                                drawMe.draw(gg);
                            }
                        }
                    }
                }
            });
            threads[j].start();
        }

        try
        {
            for (int j = 0; j < 8; ++j)
                threads[j].join();
        }
        catch (InterruptedException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    else
    {
        for (Drawable drawMe : game.drawables)
        {
            if (drawMe.isOnScreen())
            {
                drawMe.draw(g);
            }
        }
    }
}

4 个答案:

答案 0 :(得分:3)

正如已经指出的那样,synchronized (gg)正在有效地序列化所有绘图,因此由于线程创建和其他开销,您可能比单线程代码更慢。< / p>

我写的主要原因是Swing,这可能是 线程安全。所以这个程序的行为不仅可能很糟糕,而且还没有定义。

这样的线程错误在一些具有一些java运行时参数和一些图形驱动程序的机器上变成了一种棘手的行为。到过那里。做完了。不好。

JOGL将让您直接访问GPU,这是加速渲染的最可靠方法。

答案 1 :(得分:1)

要做到这一点,你可以先把每个drawMe放在一个(正确同步的)列表中,然后在连接完成后实际绘制它们。你无法加快绘图速度(尽管你已经淘汰了99%的drawMe,你已经大大减少了所需的时间),但是如果isOnScreen()有点复杂,你会得到一些真正的工作你的核心。

ConcurrentLinkedQueue可以节省同步添加到列表的需要。

下一步可能是使用阻塞队列而不是列表,因此绘制代码可以与可见性检查并行运行。运行八次检查后,它们应该远远超出图纸。 (但我认为所有阻塞队列都需要同步或自己同步。我会跳过这个并坚持使用CLQ和第一个解决方案。更简单,也可能更快。)

并且(正如Gene指出的那样),Swing相关的一切都在EventQueue上开始。把它放在那里或生活会变得奇怪。只有您自己的代码引用UI,才能在您的主题中运行。

答案 2 :(得分:0)

由于你还没有绘制任何屏幕外的物体,你可能会通过做你正在做的事情而获得很少的东西。

我甚至会说你让它变得更糟,但是引入速度慢的synchronize并引入导致上下文切换的线程,这些都很昂贵。

为了提高性能,您应该考虑使用不同的绘图库,例如Java2D绘图库,它是JDK的一部分:http://java.sun.com/products/java-media/2D/index.jsp

答案 3 :(得分:-1)

我不确定java会如何处理这个问题,但是如果你像final int n那样在范围内引用某些东西,那么其他语言将会爆炸性地死亡(因为它在循环时超出了范围)停止)。考虑将其作为可运行对象的字段。此外,在进行所有实际工作时,您正在同步图形对象。很可能你没有从中获得任何真正的性能提升。您可能会受益于显式检查对象是否并行显示在屏幕上,这是一个只读操作,将屏幕上的对象添加到其他类别的集合或集合中,然后按顺序呈现。