好的,所以我一直在看一些代码(我在上一个关于卡拉OK计时器的问题中发布的代码)
使用该代码,我建立了一些测量系统,
System.nanoTime()通过
System.out.println()它可以帮助我们了解正在发生的事情:
import java.awt.BorderLayout;import java.awt.Color;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.util.ArrayList;import javax.swing.AbstractAction;import javax.swing.JButton;import javax.swing.Jframe;import javax.swing.JOptionPane;import javax.swing.JTextPane;import javax.swing.SwingUtilities;import javax.swing.Timer;import javax.swing.text.Style;import javax.swing.text.StyleConstants;import javax.swing.text.Styleddocument;public class KaraokeTest { private int[] timingsArray = {1000, 1000, 9000, 1000, 1000, 1000, 1000, 1000, 1000, 1000};//word/letters timings private String[] individualWordsToHighlight = {" nHellon", " worldn", " Hello", " world", " Hello", " world", " Hello", " world", " Hello", " world"};//each individual word/letters to highlight private int count = 0; private final JTextPane jtp = new JTextPane(); private final JButton startButton = new JButton("Start"); private final Jframe frame = new Jframe(); //create Arrays of individual letters and their timings final ArrayList<String> chars = new ArrayList<>(); final ArrayList<Long> charsTiming = new ArrayList<>(); public KaraokeTest() { initComponents(); } private void initComponents() { frame.setDefaultCloseOperation(Jframe.EXIT_ON_CLOSE); frame.setResizable(false); for (String s : individualWordsToHighlight) { String tmp = jtp.getText(); jtp.setText(tmp + s); } jtp.setEditable(false); startButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { startButton.setEnabled(false); count = 0; charsTiming.clear(); chars.clear(); for (String s : individualWordsToHighlight) { for (int i = 0; i < s.length(); i++) { chars.add(String.valueOf(s.charAt(i))); //System.out.println(String.valueOf(s.charAt(i))); } } //calculate each letters timings for (int x = 0; x < timingsArray.length; x++) { for (int i = 0; i < individualWordsToHighlight[x].length(); i++) { individualWordsToHighlight[x] = individualWordsToHighlight[x].replace("n", " ").replace("r", " ");//replace line breaks charsTiming.add((long) (timingsArray[x] / individualWordsToHighlight[x].trim().length()));//dont count spaces //System.out.println(timingsArray[x] / individualWordsToHighlight[x].length()); } } Timer t = new Timer(1, new AbstractAction() { long startTime = 0; long acum = 0; long timeItTookTotal = 0; long dif = 0, timeItTook = 0, timeToTake = 0; int delay = 0; @Override public void actionPerformed(ActionEvent ae) { if (count < charsTiming.size()) { if (count == 0) { startTime = System.nanoTime(); System.out.println("Started: " + startTime); } timeToTake = charsTiming.get(count); acum += timeToTake; //highlight the next word highlightNextWord(); //System.out.println("Acum " + acum); timeItTook = (acum - ((System.nanoTime() - startTime) / 1000000)); timeItTookTotal += timeItTook; //System.out.println("Elapsed since start: " + (System.nanoTime() - startTime)); System.out.println("Time the char should take: " + timeToTake); System.out.println("Time it took: " + timeItTook); dif = (timeToTake - timeItTook); System.out.println("Difference: " + dif); //System.out.println("Difference2 " + (timeToTake - dif)); //calculate start of next letter to highlight less the difference it took between time it took and time it should actually take delay = (int) (timeToTake - dif); if (delay < 1) { delay = 1; } //restart timer with new timings ((Timer) ae.getSource()).setInitialDelay((int) timeToTake);//timer is usually faster thus the entire highlighting will be done too fast //((Timer) ae.getSource()).setInitialDelay(delay); ((Timer) ae.getSource()).restart(); } else {//we are at the end of the array long timeStopped = System.nanoTime(); System.out.println("Stopped: " + timeStopped); System.out.println("Time it should take in total: " + acum); System.out.println("Time it took using accumulator of time taken for each letter: " + timeItTookTotal + "nDifference: " + (acum - timeItTookTotal)); long timeItTookUsingNanoTime = ((timeStopped - startTime) / 1000000); System.out.println("Time it took using difference (endTime-startTime): " + timeItTookUsingNanoTime + "nDifference: " + (acum - timeItTookUsingNanoTime)); reset(); ((Timer) ae.getSource()).stop();//stop the timer } count++;//increment counter } }); t.setRepeats(false); t.start(); } }); frame.add(jtp, BorderLayout.CENTER); frame.add(startButton, BorderLayout.SOUTH); frame.pack(); frame.setVisible(true); } private void reset() { startButton.setEnabled(true); jtp.setText(""); for (String s : individualWordsToHighlight) { String tmp = jtp.getText(); jtp.setText(tmp + s); } JOptionPane.showMessageDialog(frame, "Done"); } private void highlightNextWord() { //we still have words to highlight int sp = 0; for (int i = 0; i < count + 1; i++) {//get count for number of letters in words (we add 1 because counter is only incrementd after this method is called) sp += 1; } while (chars.get(sp - 1).equals(" ")) { sp += 1; count++; } //highlight words Style style = jtp.addStyle("RED", null); StyleConstants.setForeground(style, Color.RED); ((Styleddocument) jtp.getdocument()).setCharacterAttributes(0, sp, style, true); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { new KaraokeTest(); } }); }}我的电脑上的输出是:
开始于:10289712615974
字符应花费的时间:166
花费时间:165
差异1
…
字符应花费的时间:166
花费时间:155
差异11
…
字符应花费的时间:166
花费时间:5
差异161
停止:10299835063084
总耗时:9960
使用每个字母所用时间的累加器所花费的时间:5542
差异:4418
使用差异所花费的时间(endTime-startTime):10122
差异:-162
因此,我的结论是Swing
Timer实际上运行的速度比我们预期的要快,因为
Timers中的代码
actionPerformed不一定要花预期的字母突出显示时间的时间,这当然会引起雪崩效应,即,计时器运行的越快/越慢,则运行时间越大/差异将变小,下次执行的计时器
restart(..)将在不同的时间进行,即更快或更慢。
在代码中执行以下操作:
//calculate start of next letter to highlight less the difference it took between time it took and time it should actually takedelay = (int) (timeToTake - dif);//restart timer with new timings//((Timer) ae.getSource()).setInitialDelay((int)timeToTake);//timer is usually faster thus the entire highlighting will be done too fast((Timer) ae.getSource()).setInitialDelay(delay);((Timer) ae.getSource()).restart();
产生更准确的结果(Ive的最大延迟是每个字母快4毫秒):
开始:10813491256556
字符应花费的时间:166
花费时间:164
差异2
…
字符应花费的时间:166
花费时间:164
差异2
…
字符应花费的时间:166
花费时间:162
差异4
停止:10823452105363
总耗时:9960
使用每个字母所用时间的累加器所花费的时间:9806
差异:154
使用差异所花费的时间(endTime-startTime):9960
差异:0



