【问题标题】:Java Swing: Improving cursor response using ThreadsJava Swing:使用线程改进光标响应
【发布时间】:2018-02-27 06:09:38
【问题描述】:

我需要加快悬停在一堆矩形上的光标响应。随着矩形数量(或复杂性)的增加,迭代矩形的直接线性算法开始恶化。

这个超链接显示的是线性搜索模型(记得加break关键字!!!)linear approach

为了清楚地说明我的意思,下面是具有两组矩形的 JPanel 的代码。第一组是 y 轴上的矩形列表,第二组是 x 轴上的矩形列表.

请记住,我的解决方案是我能想到的最好的解决方案,即使用 两个 线程同时迭代;每个列表一个线程,一个用于 x 轴,另一个用于 y 轴。我放弃的次优解决方案(代码未显示)是循环中有一个循环。一个循环专用于 x 轴矩形,另一个循环用于 y 轴矩形。我认为这是次优的搜索对于 y 轴矩形,通过 contains() 方法(假设内部循环专用于 y 轴矩形)通过首先循环所有 x 轴矩形来施加过度开销。

为了改进线性模型,我想到了这种线程方法来同时使用工作线程。

顺便说一句,我是 java 新手,尤其是多线程方面。

问题: 一个线程似乎干扰了另一个线程的性能。下面的算法由两个扩展 Thread 的包装类实现,它们都有一个迭代矩形的方法。如果另一个被注释掉,它们都可以很好地工作,即每个都很好 单独单独,但是当两者同时启动时,性能会受到影响。

如果我 join() 一个线程,那不是恢复到 线性模型,随着矩形复杂度的增加,这是一种糟糕的搜索算法?

(复杂性不仅意味着水平和垂直,还包括对角线等矩形)?

public class FlyingSaucer extends JPanel {
    Rectangle2D rec;
    Rectangle2D rec1; 
    List<Rectangle2D> recList;
    List<Rectangle2D> recList2;

    Rectangle2D.Double mouseBoxx;  
    int f = 10;
    int g = 0;
    int s = 10;
    int y = 5;
    int z = 500;

    public FlyingSaucer(){

        //FlyingSaucer needs to quickly identify specific points over given areas
        //enclosed in rectangles.They use a 'divide and conquer' approach where 
        //different types of rectangles are first identified and a worker thread
        //assigned to each category

        mouseBoxx = new Rectangle.Double();
        recList = new ArrayList<>();
        recList2 = new ArrayList<>();

        for(int i = 0; i < 15; i++){
            rec = new Rectangle2D.Double(2+f,10+g,5,1000);       
            f +=50;
            recList.add(rec);                
        }
        f = 10;

        for(int i = 0; i < 20; i++){
            rec1 = new Rectangle2D.Double(2+y,10+s,1000,5);       
            s +=35;
            recList2.add(rec1);                
        }
        s = 10;
    }


    public static void main(String[] args) {
        JFrame frame = new JFrame();
        FlyingSaucer fs = new FlyingSaucer();
        Laser laser = new Laser(fs);
        fs.addMouseMotionListener(laser);
        fs.addMouseListener(laser);
        frame.getContentPane().add(fs);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(700,700);
        frame.setVisible(true);     
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g); 
        ((Graphics2D)g).setColor(Color.RED);
        int a = 10;
        int b = 10;

        for(int i = 0;i < recList.size();i++){               
           ((Graphics2D)g).draw(recList.get(i));
        }

        for(int i = 0;i < recList2.size();i++){               
           ((Graphics2D)g).draw(recList2.get(i));
        }
    }
}


class Laser implements MouseListener,MouseMotionListener{
    Rectangle2D.Double mouseBox;
    Rectangle2D.Double recx;
    Rectangle2D.Double recy;
    FlyingSaucer fs;
    public Laser(FlyingSaucer fs){
        this.fs = fs;
    }

    @Override public void mouseClicked (MouseEvent e) { }
    @Override public void mousePressed (MouseEvent e) { }
    @Override public void mouseReleased(MouseEvent e) { }
    @Override public void mouseEntered (MouseEvent e) { }
    @Override public void mouseExited  (MouseEvent e) { }
    @Override public void mouseDragged (MouseEvent e) { }

    @Override
    public void mouseMoved(MouseEvent e) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                double x = e.getX();
                double y = e.getY();

                mouseBox = fs.mouseBoxx;
                mouseBox = new Rectangle2D.Double(x-5,y-5,10,10);

                Graphics g = fs.getGraphics();
                ((Graphics2D)g).setColor(Color.BLACK);
                ((Graphics2D)g).draw(mouseBox);

                //thread one for horizontal rectangles
                HorizontalBuffer hb = new HorizontalBuffer(fs,e);
                hb.start();

                //thread two for vertical rectangles
                VerticalBuffer vb = new VerticalBuffer(fs,e);
                vb.start();

                fs.repaint();
                g.dispose();
        }});
    }

    class HorizontalBuffer extends Thread{
        FlyingSaucer fs;
        MouseEvent e;
        List<Rectangle2D> recX;

        public HorizontalBuffer(FlyingSaucer fs,MouseEvent e){
            this.fs = fs;
            this.e = e;
        }

        public void run() {
            recX = fs.recList;
            Iterator <Rectangle2D> recs = recX.iterator();  
            int v = 1;
            while(recs.hasNext()){
                recx = (Rectangle2D.Double) recs.next();
                if(recx.contains(e.getPoint())){
                    System.out.println("X rectangle detected.."+v);
                     fs.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
                    break;
                }
                else {fs.setCursor(Cursor.getDefaultCursor());}

                v++;
            }
        }
    }

    class VerticalBuffer extends Thread{
        FlyingSaucer fs;
        MouseEvent e;
        //List<Rectangle2D> recX;
        List<Rectangle2D> recY;

        public VerticalBuffer(FlyingSaucer fs,MouseEvent e){
            this.fs = fs;
            this.e = e;
        }

        public void run(){
            recY = fs.recList2;
            Iterator <Rectangle2D> recs = recY.iterator();  
            int v = 1;
            while(recs.hasNext()){
                recy = (Rectangle2D.Double) recs.next();
                if(recy.contains(e.getPoint())){
                    System.out.println("Y rectangle detected.."+v);
                    fs.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
                    break;
                }
                else {fs.setCursor(Cursor.getDefaultCursor());}

                v++;
            }
        }
    }
}

【问题讨论】:

  • 在下次发布问题之前,请确保您的缩进是正确的。这次我给你修好了。
  • 感谢@Michael,在这里发布问题仍然是新人,并且正在努力如何发布代码。现在我看到了我发布的内容与您如何编辑它的不同之处。再次感谢。
  • 你设置光标的方式很奇怪。如果鼠标在垂直矩形之一上但不在任何水平矩形上会发生什么?使用您当前的代码,具体取决于最后一次 fs.setCursor(); 调用的线程,它将是手形光标或默认光标...
  • 你能解释一下“加速光标”是什么意思吗?当前的行为是什么,期望的行为是什么,它们有何不同?
  • 嗯,在我的一个项目中,我有数千个图形对象(不仅是与 x / y 轴对齐的矩形,还有对角线以及曲线段),并且对所有对象的线性迭代从未导致不使用线程的性能问题。您显示的代码总共有 35 个矩形,所以在我看来,您的线程带来的问题多于解决的问题。

标签: java multithreading swing jpanel


【解决方案1】:

您的 FlyingSaucer 类不是线程安全的,但您从两个不同的线程(Horizo​​ntalBuffer 和 VerticalBuffer)访问它。这可能会导致问题:例如,当 Horizo​​ntalBuffer 尝试获取 FlyingSaucer reclist 时,它可能会变为 null 并引发异常。由于访问不同步,也可能出现其他问题。这不是最容易调试的事情:例如,除非您正在查看控制台,否则您不会知道异常,因为一个线程中的异常不会终止多线程程序。

您可以通过使 FlyingSaucer 线程安全、正确同步对它的访问来解决这个特定的访问同步问题。但是,也可能存在其他问题;让多线程应用程序正常工作并不简单,对于 Java 新手来说可能不是最好的方法,就像你说的那样。

正如 cmets 中的其他人所指出的,最好的解决方案可能不是多线程。我建议使用您的单线程解决方案发布一个新问题,并询问如何加快速度。您可以在该问题中提及多线程,但我建议您也对其他解决方案持开放态度。

【讨论】:

  • 好吧,确实它可能不是线程安全的。我将用同步的向量替换列表和数组列表。我承认我的多线程尝试远高于我的工资等级,但是当然,我们通过尝试、犯错误和纠正错误来学习。我按照您的建议发布了一个新问题,感谢您的指导。
  • @ThomasKlugerREVISED QUESTIONThank peoples
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-27
  • 1970-01-01
  • 2011-12-21
相关资源
最近更新 更多