简体   繁体   中英

Is it possible to have too much work on the EDT?

This sample constantly draws squares of various color. The number of squares is based on the size of the JFrame.

While the example is executing, use the mouse to enlarge or shrink the size frame and it will increase or decrease the number of visible blinking squares.

The time bar for the frame displays the time. This example also has a System.out.println in the draw() routine.

The objective isn't to discuss how poorly written is this example but rather to use as a tool to pose a question.

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class LotsOfSquares  extends JPanel 
{

  Random rand = new Random();
  static JFrame frame = new JFrame("Lots Of Squares ");
  int numOfSquares = 0;

  public void paintComponent(Graphics g) 
  {
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D) g;

    int sizeOfSquare = 5;

    numOfSquares = 0;
    for (int x=0; x<frame.getSize().width; x = x + sizeOfSquare )
    {
        numOfSquares ++;
        for (int y=0; y<frame.getSize().height; y = y + sizeOfSquare )
        {
            g2d.setColor(new Color(rand.nextFloat(), rand.nextFloat(), rand.nextFloat()));
            g2d.fillRect(x, y, sizeOfSquare, sizeOfSquare);
            numOfSquares ++;
            System.out.println("   Displaying " + numOfSquares + " squares within Inner Loop");
        }
    }
    //System.out.println("   Displaying " + numOfSquares + " squares total");
  }

  public static void main(String[] args) 
  {
LotsOfSquares  rects = new LotsOfSquares ();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.add(rects);
    frame.setSize(360, 300);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);

    TimerTask repeatedTask = new TimerTask() 
    {
        public void run() 
        {
            //System.out.println("Task performed on " + new Date());
            frame.repaint();
        }
    };

    Timer timer = new Timer("Refresh Timer");
    long delay  = 1000L;
    long period = 150L;
    timer.scheduleAtFixedRate(repeatedTask, delay, period);


    TimerTask clockTask = new TimerTask() 
    {
        public void run() 
        {
         SimpleDateFormat timeFormat = new SimpleDateFormat("hh:mm:ss");
            Calendar currentCalendar = Calendar.getInstance();
            Date currentTime = currentCalendar.getTime();
            SwingUtilities.invokeLater(new Runnable() 
            {
              public void run()
              {
                  frame.setTitle(timeFormat.format(currentTime) );
              }
            });
          }
    };

    Timer clockTimer= new Timer("Clock Timer");
    long clockDelay  = 1000L;
    long clockPeriod = 1000L;
    clockTimer.scheduleAtFixedRate(clockTask, clockDelay, clockPeriod);
  }
}

When the program starts, the frame is small and the squares blink at a constant rate, the clock ticks right on time and the System.out command is being output fine.

This example works best with 2-3 monitors.

As the frame is expanded, the number of blinking squares increases and starts to blink much more slowly and the clock starts skipping seconds.

Question:

Simply commenting out the inner loop System.out call : System.out.println(" Displaying " + numOfSquares + " squares within Inner Loop"); and removing the comment for the outer loop System.out call : System.out.println(" Displaying " + numOfSquares + " squares total"); makes a significant improvement.

This tells me the EDT is simply unable to handle the workload even if attributed to the way the code is written. If a scenario like this were to arise, is it possible to smooth out the blinking and get the clock to not skip a beat?

Removing the frame.setTitle(timeFormat.format(currentTime) ); from the EDT works great for the clock but squares still blink more slowly.

Assuming this example meets an application requirements, what could be done to have the squares blink with a large frame as it does with a small frame as well as prevent the clock from skipping seconds?

At what point, do you state, the application is simply asking the JVM and EDT to do too much?

You can draw on some other thread and then just pass the resulting Image to be painted in the component. This way you can offload the work to some other thread, releasing the EDT from performing heavy tasks. You can use multiple threads for preparing the desired image, that's up to you. This is the way how I ususually handle drawings that needs a lot of power to have better frame rate.

In your example I would create some Exacutor with a numer of threads, and create some Future that would create the BufferedImage for you, then you fed the executor with a number of these tasks, and when you get the ready BufferedImage pass it to the component to be drawn. In this way you can have greater performance. How many threads to have in the executor, or when to feed the executor with new tasks is left to the OP for consideration.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM