2013-11-09 4 views
2


Я пытаюсь реализовать секундомер, аналогичный найденному в Is there a stopwatch in Java?, но как Thread.

My SecondsCounter класс реализует Runnable, и при вызове его метода «start» создается поток как локальная переменная.

Казалось бы, как если бы эта нить конфликтует с первой строки в run метода:   this.runningTime = System.currentTimeMillis(); ... потому что условие while (this.runningTime < this.endTime) является никогда сломана (бесконечный цикл) ...

Так неверно ли иметь класс, который реализует Runnableи содержит его 'Thread?

Как сделать секундомер как поток в Java?



Вот класс с основным методом:

public class MultithreadingTest { 

    public static void main(String[] args) { 
     int totalSeconds = 5; 
     SecondsPrinter printer = new SecondsPrinter(totalSeconds); 
     printer.startPrinting(); 
    } 
} // end of class 


... класс секунд принтер:

public class SecondsPrinter { 

    // composition here: 
    private SecondsCounter clock; 

    public SecondsPrinter(int totalSeconds) { 
     this.clock = new SecondsCounter(totalSeconds); 
    } 

    public void startPrinting() { 
     this.clock.start(); 
     while (this.clock.isRunning()) { 

      // this is incorrectly always printing the maximum seconds value: 
      System.out.println(this.clock.getCurrentSecond()); 
     } 
    } 
} // end of class 


... и класс счетчик секунд :

public class SecondsCounter implements Runnable { 

    private int totalSeconds, currentSecond; 
    private long startTime, runningTime, endTime; 
    private Thread thread; 

    public SecondsCounter(int totalSeconds) { 
     this.totalSeconds = totalSeconds; 
    } 

    public int getCurrentSecond() { 
     return this.currentSecond; 
    } 

    @Override 
    public void run() { 
     this.runningTime = System.currentTimeMillis(); 

     // this is an infinite loop, but it shouldn't be: 
     while (this.runningTime < this.endTime) { 
      this.currentSecond = (int)(this.endTime - this.runningTime)/1000; 
     } 

     // this code is never reached: 
     this.stop(); 
    } 

    public void start() { 
     this.startTime = System.currentTimeMillis(); 
     this.runningTime = this.startTime; 
     this.endTime = this.startTime + (this.totalSeconds * 1000); 

     // multithreading here: 
     this.thread = new Thread(this); 
     this.thread.start(); 
    } 

    public boolean isRunning() { 
     return this.thread.isAlive(); 
    } 

    public void stop() { 
     this.thread.interrupt(); 
     this.thread = null; 
    } 
} // end of class 
+0

То есть много кода. Я бы рассмотрел, как вы могли бы упростить его, чтобы делать то, что вы хотите. –

+0

@PeterLawrey - Хм, я мог бы исключить переменную 'startTime' в классе' SecondsCounter' и, возможно, передать миллисекунды вместо секунд своему конструктору, чтобы упростить некоторые элементы преобразования единиц. Я мог бы просто использовать 'java.util.Timer' вместо этого, но я делаю это только для экспериментов с потоками. В противном случае я не замечаю никакого * разделения проблем * проблем или нарушений * СУХОЙ *. Что вы могли бы предложить? –

ответ

4

На самом деле это должен быть бесконечный цикл. Посмотрите на свою петлю.

while (this.runningTime < this.endTime) { 
    this.currentSecond = (int)(this.endTime - this.runningTime)/1000; 
} 

Состояние говорит о том, что оно будет проходить в то время как runningTime < endTime. Где обновляется runningTime? Если добавить что-то вроде этого в петлю, он должен работать:

public void run() { 
    this.runningTime = System.currentTimeMillis(); 

    // no longer an infinite loop 
    while (this.runningTime < this.endTime) { 
     this.currentSecond = (int)(this.endTime - this.runningTime)/1000; 
     this.runningTime = System.currentTimeMillis(); 
    } 

    // this code is now reached. 
    this.stop(); 
} 

Вы могли бы даже объединить его (или удалить переменную runningTime в целом):

public void run() { 
    while ((this.runningTime = System.currentTimeMillis()) < this.endTime) { 
     this.currentSecond = (int)(this.endTime - this.runningTime)/1000; 
    } 

    this.stop(); 
} 
+0

О, я полностью пропустил это, да! Теперь он работает правильно, спасибо @Quincunx за помощь. –

+0

Интересно, я не знал, что вы оба можете установить, а затем использовать значение как условие while-loop, спасибо @Quincunx! Это * только *, похоже, работает, когда параметр находится в круглых скобках, например: 'while ((this.runningTime = System.currentTimeMillis())

+1

@IanCampbell Это работает, потому что оператор присваивания также возвращает значение, которое он присваивает. Он работает только с круглыми скобками, потому что операторы присваивания имеют самую низкую [точность выполнения] (http://docs.oracle.com/javase/tutorial/java/nutsandbolts/operators.html), поэтому без круглых скобок мы получаем 'this. runTime = (System.currentTimeMillis() Justin

Смежные вопросы