解析Java中的准時器及應用准時器制造彈彈球游戲的示例。本站提示廣大學習愛好者:(解析Java中的准時器及應用准時器制造彈彈球游戲的示例)文章只能為提供參考,不一定能成為您想要的結果。以下是解析Java中的准時器及應用准時器制造彈彈球游戲的示例正文
在我們編程進程中假如須要履行一些簡略的准時義務,不必做龐雜的掌握,我們可以斟酌應用JDK中的Timer准時義務來完成。上面LZ就其道理、實例和Timer缺點三個方面來解析java Timer准時器。
1、簡介
在java中一個完全准時義務須要由Timer、TimerTask兩個類來合營完成。 API中是如許界說他們的,Timer:一種對象,線程用其支配今後在後台線程中履行的義務。可支配義務履行一次,或許按期反復履行。由TimerTask:Timer 支配為一次履行或反復履行的義務。我們可以如許懂得Timer是一種准時器對象,用來在一個後台線程籌劃履行指定義務,而TimerTask一個籠統類,它的子類代表一個可以被Timer籌劃的義務。
Timer類
在對象類Timer中,供給了四個結構辦法,每一個結構辦法都啟動了計時器線程,同時Timer類可以包管多個線程可以同享單個Timer對象而無需停止內部同步,所以Timer類是線程平安的。然則因為每個Timer對象對應的是單個後台線程,用於次序履行一切的計時器義務,普通情形下我們的線程義務履行所消費的時光應當異常短,然則因為特別情形招致某個准時器義務履行的時光太長,那末他就會“獨有”計時器的義務履行線程,厥後的一切線程都必需期待它履行完,這就會延遲後續義務的履行,使這些義務聚積在一路,詳細情形我們前面剖析。
當法式初始化完成Timer後,准時義務就會依照我們設定的時光去履行,Timer供給了schedule辦法,該辦法有多中重載方法來順應分歧的情形,以下:
schedule(TimerTask task, Date time):支配在指定的時光履行指定的義務。
schedule(TimerTask task, Date firstTime, long period) :支配指定的義務在指定的時光開端停止反復的固定延遲履行。
schedule(TimerTask task, long delay) :支配在指定延遲後履行指定的義務。
schedule(TimerTask task, long delay, long period) :支配指定的義務從指定的延遲後開端停止反復的固定延遲履行。
同時也重載了scheduleAtFixedRate辦法,scheduleAtFixedRate辦法與schedule雷同,只不外他們的著重點分歧,差別前面剖析。
scheduleAtFixedRate(TimerTask task, Date firstTime, long period):支配指定的義務在指定的時光開端停止反復的固定速度履行。
scheduleAtFixedRate(TimerTask task, long delay, long period):支配指定的義務在指定的延遲後開端停止反復的固定速度履行。
TimerTask
TimerTask類是一個籠統類,由Timer 支配為一次履行或反復履行的義務。它有一個籠統辦法run()辦法,該辦法用於履行響應計時器義務要履行的操作。是以每個詳細的義務類都必需繼續TimerTask,然後重寫run()辦法。
別的它還有兩個非籠統的辦法:
boolean cancel():撤消此計時器義務。
long scheduledExecutionTime():前往此義務比來現實履行的支配履行時光。
2、實例
2.1、指定延遲時光履行准時義務
public class TimerTest01 { Timer timer; public TimerTest01(int time){ timer = new Timer(); timer.schedule(new TimerTaskTest01(), time * 1000); } public static void main(String[] args) { System.out.println("timer begin...."); new TimerTest01(3); } } public class TimerTaskTest01 extends TimerTask{ public void run() { System.out.println("Time's up!!!!"); } }
運轉成果:
起首打印:
timer begin....
3秒後打印:
Time's up!!!!
2.2、在指准時間履行准時義務
public class TimerTest02 { Timer timer; public TimerTest02(){ Date time = getTime(); System.out.println("指准時間time=" + time); timer = new Timer(); timer.schedule(new TimerTaskTest02(), time); } public Date getTime(){ Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.HOUR_OF_DAY, 11); calendar.set(Calendar.MINUTE, 39); calendar.set(Calendar.SECOND, 00); Date time = calendar.getTime(); return time; } public static void main(String[] args) { new TimerTest02(); } } public class TimerTaskTest02 extends TimerTask{ @Override public void run() { System.out.println("指准時間履行線程義務..."); } }
其時間達到11:39:00時就會履行該線程義務,固然年夜於該時光也會履行!!履行成果為:
指准時間time=Tue Jun 10 11:39:00 CST 2014 指准時間履行線程義務...
2.3、在延遲指准時間後以指定的距離時光輪回履行准時義務
public class TimerTest03 { Timer timer; public TimerTest03(){ timer = new Timer(); timer.schedule(new TimerTaskTest03(), 1000, 2000); } public static void main(String[] args) { new TimerTest03(); } } public class TimerTaskTest03 extends TimerTask{ @Override public void run() { Date date = new Date(this.scheduledExecutionTime()); System.out.println("本次履行該線程的時光為:" + date); } }
運轉成果:
本次履行該線程的時光為:Tue Jun 10 21:19:47 CST 2014 本次履行該線程的時光為:Tue Jun 10 21:19:49 CST 2014 本次履行該線程的時光為:Tue Jun 10 21:19:51 CST 2014 本次履行該線程的時光為:Tue Jun 10 21:19:53 CST 2014 本次履行該線程的時光為:Tue Jun 10 21:19:55 CST 2014 本次履行該線程的時光為:Tue Jun 10 21:19:57 CST 2014 .................
關於這個線程義務,假如我們不將該義務停滯,他會一向運轉下去。
關於下面三個實例,LZ只是簡略的演示了一下,同時也沒有講授scheduleAtFixedRate辦法的例子,其實該辦法與schedule辦法一樣!
2.4、剖析schedule和scheduleAtFixedRate
(1)schedule(TimerTask task, Date time)、schedule(TimerTask task, long delay)
關於這兩個辦法而言,假如指定的籌劃履行時光scheduledExecutionTime<= systemCurrentTime,則task會被立刻履行。scheduledExecutionTime不會由於某一個task的過度履行而轉變。
(2)schedule(TimerTask task, Date firstTime, long period)、schedule(TimerTask task, long delay, long period)
這兩個辦法與下面兩個就有點兒分歧的,後面提過Timer的計時器義務會由於前一個義務履行時光較長而延時。在這兩個辦法中,每次履行的task的籌劃時光會跟著前一個task的現實時光而產生轉變,也就是scheduledExecutionTime(n+1)=realExecutionTime(n)+periodTime。也就是說假如第n個task因為某種情形招致此次的履行時光進程,最初招致systemCurrentTime>= scheduledExecutionTime(n+1),這是第n+1個task其實不會由於到時了而履行,他會期待第n個task履行完以後再履行,那末如許必將會招致n+2個的履行完成scheduledExecutionTime放生轉變即scheduledExecutionTime(n+2) = realExecutionTime(n+1)+periodTime。所以這兩個辦法加倍重視保留距離時光的穩固。
(3)scheduleAtFixedRate(TimerTask task, Date firstTime, long period)、scheduleAtFixedRate(TimerTask task, long delay, long period)
在後面也提過scheduleAtFixedRate與schedule辦法的著重點分歧,schedule辦法著重保留距離時光的穩固,而scheduleAtFixedRate辦法加倍著重於堅持履行頻率的穩固。為何這麼說,緣由以下。在schedule辦法中會由於前一個義務的延遲而招致厥後面的准時義務延時,而scheduleAtFixedRate辦法則不會,假如第n個task履行時光太長招致systemCurrentTime>= scheduledExecutionTime(n+1),則不會做任多麼待他會立刻履行第n+1個task,所以scheduleAtFixedRate辦法履行時光的盤算辦法分歧於schedule,而是scheduledExecutionTime(n)=firstExecuteTime +n*periodTime,該盤算辦法永久堅持不變。所以scheduleAtFixedRate加倍著重於堅持履行頻率的穩固。
3、Timer的缺點
3.1、Timer的缺點
Timer計時器可以准時(指准時間履行義務)、延遲(延遲5秒履行義務)、周期性地履行義務(每隔個1秒履行義務),然則,Timer存在一些缺點。起首Timer對換度的支撐是基於相對時光的,而不是絕對時光,所以它對體系時光的轉變異常敏感。其次Timer線程是不會捕捉異常的,假如TimerTask拋出的了未檢討異常則會招致Timer線程終止,同時Timer也不會從新恢單線程的履行,他會毛病的以為全部Timer線程都邑撤消。同時,曾經被支配單還沒有履行的TimerTask也不會再履行了,新的義務也不克不及被調劑。故假如TimerTask拋出未檢討的異常,Timer將會發生沒法預感的行動。
(1)Timer治理時光延遲缺點
後面Timer在履行准時義務時只會創立一個線程義務,假如存在多個線程,若個中某個線程由於某種緣由而招致線程義務履行時光太長,跨越了兩個義務的距離時光,會產生一些缺點:
public class TimerTest04 { private Timer timer; public long start; public TimerTest04(){ this.timer = new Timer(); start = System.currentTimeMillis(); } public void timerOne(){ timer.schedule(new TimerTask() { public void run() { System.out.println("timerOne invoked ,the time:" + (System.currentTimeMillis() - start)); try { Thread.sleep(4000); //線程休眠3000 } catch (InterruptedException e) { e.printStackTrace(); } } }, 1000); } public void timerTwo(){ timer.schedule(new TimerTask() { public void run() { System.out.println("timerOne invoked ,the time:" + (System.currentTimeMillis() - start)); } }, 3000); } public static void main(String[] args) throws Exception { TimerTest04 test = new TimerTest04(); test.timerOne(); test.timerTwo(); } }
依照我們正常思緒,timerTwo應當是在3s後履行,其成果應當是:
timerOne invoked ,the time:1001 timerOne invoked ,the time:3001
然則適得其反,timerOne因為sleep(4000),休眠了4S,同時Timer外部是一個線程,招致timeOne所需的時光跨越了距離時光,成果:
timerOne invoked ,the time:1000 timerOne invoked ,the time:5000
(2)Timer拋出異常缺點
假如TimerTask拋出RuntimeException,Timer會終止一切義務的運轉。以下:
public class TimerTest04 { private Timer timer; public TimerTest04(){ this.timer = new Timer(); } public void timerOne(){ timer.schedule(new TimerTask() { public void run() { throw new RuntimeException(); } }, 1000); } public void timerTwo(){ timer.schedule(new TimerTask() { public void run() { System.out.println("我會不會履行呢??"); } }, 1000); } public static void main(String[] args) { TimerTest04 test = new TimerTest04(); test.timerOne(); test.timerTwo(); } }
運轉成果:timerOne拋出異常,招致timerTwo義務終止。
Exception in thread "Timer-0" java.lang.RuntimeException at com.chenssy.timer.TimerTest04$1.run(TimerTest04.java:25) at java.util.TimerThread.mainLoop(Timer.java:555) at java.util.TimerThread.run(Timer.java:505)
關於Timer的缺點,我們可以斟酌 ScheduledThreadPoolExecutor 來替換。Timer是基於相對時光的,對體系時光比擬敏感,而ScheduledThreadPoolExecutor 則是基於絕對時光;Timer是外部是單一線程,而ScheduledThreadPoolExecutor外部是個線程池,所以可以支撐多個義務並發履行。
3.2、用ScheduledExecutorService替換Timer
(1)處理成績一:
public class ScheduledExecutorTest { private ScheduledExecutorService scheduExec; public long start; ScheduledExecutorTest(){ this.scheduExec = Executors.newScheduledThreadPool(2); this.start = System.currentTimeMillis(); } public void timerOne(){ scheduExec.schedule(new Runnable() { public void run() { System.out.println("timerOne,the time:" + (System.currentTimeMillis() - start)); try { Thread.sleep(4000); } catch (InterruptedException e) { e.printStackTrace(); } } },1000,TimeUnit.MILLISECONDS); } public void timerTwo(){ scheduExec.schedule(new Runnable() { public void run() { System.out.println("timerTwo,the time:" + (System.currentTimeMillis() - start)); } },2000,TimeUnit.MILLISECONDS); } public static void main(String[] args) { ScheduledExecutorTest test = new ScheduledExecutorTest(); test.timerOne(); test.timerTwo(); } }
運轉成果:
timerOne,the time:1003 timerTwo,the time:2005
(2)處理成績二
public class ScheduledExecutorTest { private ScheduledExecutorService scheduExec; public long start; ScheduledExecutorTest(){ this.scheduExec = Executors.newScheduledThreadPool(2); this.start = System.currentTimeMillis(); } public void timerOne(){ scheduExec.schedule(new Runnable() { public void run() { throw new RuntimeException(); } },1000,TimeUnit.MILLISECONDS); } public void timerTwo(){ scheduExec.scheduleAtFixedRate(new Runnable() { public void run() { System.out.println("timerTwo invoked ....."); } },2000,500,TimeUnit.MILLISECONDS); } public static void main(String[] args) { ScheduledExecutorTest test = new ScheduledExecutorTest(); test.timerOne(); test.timerTwo(); } }
運轉成果:
timerTwo invoked ..... timerTwo invoked ..... timerTwo invoked ..... timerTwo invoked ..... timerTwo invoked ..... timerTwo invoked ..... timerTwo invoked ..... timerTwo invoked ..... timerTwo invoked ..... ........................
4、應用准時器完成彈彈球
模仿書上的一個例題做了一個彈彈球,是在畫布上的指定地位畫多個圓,經由一段的延時後,在鄰近地位從新畫。使球看起來是動,經由過程JSpinner組件調理延時,來掌握彈彈球的挪動速度.
BallsCanvas.java
public class BallsCanvas extends Canvas implements ActionListener, FocusListener { private Ball balls[]; // 多個球 private Timer timer; private static class Ball { int x, y; // 坐標 Color color; // 色彩 boolean up, left; // 活動偏向 Ball(int x, int y, Color color) { this.x = x; this.y = y; this.color = color; up = left = false; } } public BallsCanvas(Color colors[], int delay) { // 初始化色彩、延時 this.balls = new Ball[colors.length]; for (int i = 0, x = 40; i < colors.length; i++, x += 40) { balls[i] = new Ball(x, x, colors[i]); } this.addFocusListener(this); timer = new Timer(delay, this); // 創立准時器對象,delay指定延時 timer.start(); } // 設置延時 public void setDelay(int delay) { timer.setDelay(delay); } // 在canvas下面作畫 public void paint(Graphics g) { for (int i = 0; i < balls.length; i++) { g.setColor(balls[i].color); // 設置色彩 balls[i].x = balls[i].left ? balls[i].x - 10 : balls[i].x + 10; if (balls[i].x < 0 || balls[i].x >= this.getWidth()) { // 到程度偏向更改偏向 balls[i].left = !balls[i].left; } balls[i].y = balls[i].up ? balls[i].y - 10 : balls[i].y + 10; if (balls[i].y < 0 || balls[i].y >= this.getHeight()) { // 到垂直偏向更改偏向 balls[i].up = !balls[i].up; } g.fillOval(balls[i].x, balls[i].y, 20, 20); // 畫指定直徑的圓 } } // 准時器准時履行事宜 @Override public void actionPerformed(ActionEvent e) { repaint(); // 重畫 } // 取得核心 @Override public void focusGained(FocusEvent e) { timer.stop(); // 准時器停滯 } // 掉去核心 @Override public void focusLost(FocusEvent e) { timer.restart(); // 准時重視啟動 } }
BallsJFrame.java
class BallsJFrame extends JFrame implements ChangeListener { private BallsCanvas ball; private JSpinner spinner; public BallsJFrame() { super("彈彈球"); this.setBounds(300, 200, 480, 360); this.setDefaultCloseOperation(EXIT_ON_CLOSE); Color colors[] = { Color.red, Color.green, Color.blue, Color.magenta, Color.cyan }; ball = new BallsCanvas(colors, 100); this.getContentPane().add(ball); JPanel panel = new JPanel(); this.getContentPane().add(panel, "South"); panel.add(new JLabel("Delay")); spinner = new JSpinner(); spinner.setValue(100); panel.add(spinner); spinner.addChangeListener(this); this.setVisible(true); } @Override public void stateChanged(ChangeEvent e) { // 修正JSpinner值時,單擊JSpinner的Up或許down按鈕時,或許在JSpinner中按Enter鍵 ball.setDelay(Integer.parseInt("" + spinner.getValue())); } public static void main(String[] args) { new BallsJFrame(); } }
後果以下: