5

I am new to using the Timer class, and so am trying to experiment with it before incorporating it into my project. I am wondering why this program does not terminate when the count reaches 5. The program keeps running even though the condition for the while loop is not satisfied.

package Timer;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;

public class demo {

    private static int count;


    public static void main(String[] args) {
        ActionListener executeThis = new ActionListener(){


            @Override
            public void actionPerformed(ActionEvent arg0) {
                // TODO Auto-generated method stub
                System.out.println("Hello");
                count++;

            }

        };

        Timer timer = new Timer(500, executeThis);
        timer.setInitialDelay(1000);
        timer.start();

        while(count < 5){

        }
    }

}
lb91
  • 109
  • 9
  • why should it stop? you are executing it as a timer job. Which basically schedules it and run it after the given time interval – Danyal Sandeelo Mar 22 '16 at 09:02
  • Possible duplicate of [How to stop immediately the task scheduled in Java.util.Timer class](http://stackoverflow.com/questions/4050442/how-to-stop-immediately-the-task-scheduled-in-java-util-timer-class) – itzmukeshy7 Mar 22 '16 at 09:05
  • Why is it, then, that when I don't have a while loop, the timer never sends out an actionEvent? If the while loop is not needed why does this occur? – lb91 Mar 22 '16 at 09:09

5 Answers5

2

You should add:

timer.stop();

In order to stop the timer scheduling.

Another issue is the usage of non atomic variable in multi-threaded ennvironment. You can use AtomicInteger instead.

You can do it inside the actionPerformed method if count == 5.

BobTheBuilder
  • 18,858
  • 6
  • 40
  • 61
  • This did not work, by the way. The program still continues. – lb91 Mar 22 '16 at 09:15
  • Timer stops but program continues with your update. Some other actions are required. – RubioRic Mar 22 '16 at 09:40
  • 1
    The problem is there is the `while-loop` is never seeing the changes been made to `count` as they are on different threads, it's basically a dirty read problem – MadProgrammer Mar 22 '16 at 10:10
2

for stoping the timer

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.atomic.AtomicInteger;


public class Test1 {
    private static AtomicInteger count = new AtomicInteger(0);

    public static void main(String[] args) {
        ActionListener executeThis = new ActionListener(){


            @Override
            public void actionPerformed(ActionEvent arg0) {
                // TODO Auto-generated method stub
                System.out.println("Hello");
                count.getAndIncrement();

            }

        };

        Timer timer = new Timer(500, executeThis);
        timer.setInitialDelay(1000);
        timer.start();

        while(count.get() < 5){

        }
        timer.stop();

    }
}

but i think this will be the correct way to do this

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * User: Romeo Sheshi 
 * Date: 21/03/16
 * Time: 12:12
 */
public class Test {
    private static AtomicInteger count = new AtomicInteger(0);
    private static Timer timer;
    public static void main(String[] args) {


        ActionListener executeThis = new ActionListener(){


            @Override
            public void actionPerformed(ActionEvent arg0) {
                // TODO Auto-generated method stub
                System.out.println("Hello");

                if( count.incrementAndGet()==5){
                   stopTimer();
                }

            }

        };
        timer = new Timer(500, executeThis);
        timer.setInitialDelay(1000);
        startTimer();

        while ( count.get()<5){}

    }

    public static void startTimer(){
        timer.start();
    }

    public static void stopTimer(){
        timer.stop();
    }
}
Romeo Sheshi
  • 901
  • 5
  • 7
2

There are two issues:

  • The timer keeps running when not stopped.
  • The static count variable does not get synchronised between threads.

Check this explanation from Gray about synchronization between threads: Static variables and multithreading in java He explains that each thread has its own copy of a static variable. To avoid this declare the variable volatile.

For simple testing like this example, a volatile variable is all you need. For critical situations where you need a realtime synchronization between threads use AtomicInteger.

private static volatile int count;

Make sure to stop the timer with timer.stop(). It is not wrong to add a Thread.sleep in the loop, this safes CPU resources and allows thread synchronization for non-volatile variables.

while (count < 5) {
  Thread.sleep(10);
}    
timer.stop();

You can read more about the difference between a volatile variable and AtomicInteger here: What is the difference between atomic / volatile / synchronized?

Community
  • 1
  • 1
tak3shi
  • 2,305
  • 1
  • 20
  • 33
1

This is a supporting answer to Romeo Sheshi

This code has been test on:

  • Windows; Java 1.7.0_75 using Netbeans 8 AND the command line
  • MacOS 10.11.3; Java 1.8.0_20 using Netbeans 8 and the terminal

In both cases, the program terminated after the count reached 5

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.atomic.AtomicInteger;
import javax.swing.Timer;

public class Test {

    private static AtomicInteger count = new AtomicInteger(0);

    public static void main(String[] args) {
        ActionListener executeThis = new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                // TODO Auto-generated method stub
                System.out.println("Hello");
                count.getAndIncrement();
                System.out.println(count);
            }

        };

        Timer timer = new Timer(500, executeThis);
        timer.setInitialDelay(1000);
        timer.start();

        while (count.get() < 5) {
        }
        System.out.println("On the outside...");
        timer.stop();
    }

}
Community
  • 1
  • 1
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
-1

Best And Easiest Way to do this is --

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;

public class demo {

    private static int count;


    public static void main(String[] args) {
        ActionListener executeThis = new ActionListener(){


            @Override
            public void actionPerformed(ActionEvent arg0) {
                // TODO Auto-generated method stub
                System.out.println("Hello");
                count++;
                if(count==5){
                    System.exit(0);                 
                }
            }

        };

        Timer timer = new Timer(500, executeThis);
        timer.setInitialDelay(1000);
        timer.start();

        while(count < 5){

        }
    }

}
Community
  • 1
  • 1
Pritpal Singh
  • 163
  • 13