Timer error made with java

0

I was doing a program in java and in this I need a timer that can run on multiple occasions without closing the program however I only get it to run once before I miss an error, in the code I use 2 Timer of the class java.util.Timer and two Timer Task

    if(evt.getSource() == jButton3){
        segundos = parseInt(jTextField2.getText());
        total = segundos * 1000;

        TimerTask task1;
        task1 = new TimerTask() {
                    @Override
                    public void run() {
                        jLabel4.setText("   " + segundos);
                        if(segundos == 1){
                            JOptionPane.showMessageDialog(null," El Tiempo termino");
                            jTextArea3.setText(area.substring(10,area.length()));
                        }
                        segundos--;
                    }
                };
        t1.scheduleAtFixedRate(task1,0, 1000);

        TimerTask task2 = new TimerTask() {
                    @Override
                    public void run() {
                        t1.cancel();
                    }
                };
        t2.schedule(task2,total);
    }
}

this is the other error

Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Timer already cancelled.
    at java.util.Timer.sched(Timer.java:397)
    at java.util.Timer.scheduleAtFixedRate(Timer.java:328)
    at clases.Principal1.jButton3ActionPerformed(Principal1.java:340)
    at clases.Principal1.access$200(Principal1.java:21)
    at clases.Principal1$3.actionPerformed(Principal1.java:122)
    at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)
    at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2348)
    at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
    at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
    at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
    at java.awt.Component.processMouseEvent(Component.java:6539)
    at javax.swing.JComponent.processMouseEvent(JComponent.java:3324)
    at java.awt.Component.processEvent(Component.java:6304)
    at java.awt.Container.processEvent(Container.java:2239)
    at java.awt.Component.dispatchEventImpl(Component.java:4889)
    at java.awt.Container.dispatchEventImpl(Container.java:2297)
    at java.awt.Component.dispatchEvent(Component.java:4711)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4904)
    at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4535)
    at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4476)
    at java.awt.Container.dispatchEventImpl(Container.java:2283)
    at java.awt.Window.dispatchEventImpl(Window.java:2746)
    at java.awt.Component.dispatchEvent(Component.java:4711)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:760)
    at java.awt.EventQueue.access$500(EventQueue.java:97)
    at java.awt.EventQueue$3.run(EventQueue.java:709)
    at java.awt.EventQueue$3.run(EventQueue.java:703)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:84)
    at java.awt.EventQueue$4.run(EventQueue.java:733)
    at java.awt.EventQueue$4.run(EventQueue.java:731)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:730)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:205)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
    
asked by jhonny 25.12.2018 в 21:06
source

1 answer

0

in the provided code has Concurrence problems, for example, the code provided allows multiple Task Manipulate the value segundos not only in an insecure way (the value is not atomic, or is synchronized, not nothing) and can become a negative value (and I think this is not the desired result) so OP, you should check that your code allows a Lock and syncronize the readings and writes well.

Regarding the Reported problem, it was simple to reproduce it with the following code:

//variables globales de ejemplo
int segundos;
Timer t1 = new Timer();
Timer t2 = new Timer();
TimerTask task1, task2;

//...
//codigo de UI etc etc.
//...

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
    segundos = parseInt("10");
    int total = segundos * 1000;

    task1 = new TimerTask() {
        @Override
        public void run() {
            try{
            txtout.setText("   " + segundos);
            if (segundos == 1) {
                txtout.setText("Termino!");
            }
            segundos--;
            }catch(Exception e){
                  Logger.getLogger(ButtonPanel.class.getName()).log(Level.SEVERE, null, e);
            }
        }
    };
    t1.scheduleAtFixedRate(task1, 0, 1000);

    task2 = new TimerTask() {
        @Override
        public void run() {
            t1.cancel();
        }
    };
    t2.schedule(task2, total);
}  

problems detected:

  • there is no verification that task1 or task2 are null or existing references.
  • does not check if there are already existing tasks running and discards any task that is already executed!
  • allows Timer t1 and t2 to register new Task. This is a problem. I'm almost sure this is not what OP wants to happen ...

In this case OP requires changing the code so that the execution of Other task is not allowed until the previous one ends. but before showing how to solve First show what is happening: (I hope make it clear enough)

therefore, as shown in the previous diagram.

  • if there are 2 Task, the value of segundos is updated more than 1 time per second and you can even return a negative value
  • if 2 Task is registered in T2 this generates the Error IllegalStateException: Timer already cancelled. given that the Canceled is T1 (All the tasks not only one in particular) and given that Task2 ( 1) is registered for when it is running and T1 I cancel ALL the tasks and therefore Timer already cancelled .

how to fix it:

There are several ways.

  • check if T1 has Task that are not Canceled (Timer does not have code to do is iscancelled () or something similar so this option is ... complicated)
  • make Task2 not Cancel T1 but call Cancel in Task1 (instead of T1 canceling ALL the tasks within the timer)
  • add a Lock or Synchronized Variable that indicates if a Task is executing and does not allow Another Task to be registered.
  • (combination of 2 and 3)
  • apart from this, verify that the variables that are edited concurrently are manipulated in a secure way (syncronized or that they are atomic)

    therefore, here is an example of a possible solution:

    //variables globales
    AtomicInteger segundos = new AtomicInteger();
    Timer t1 = new Timer();
    Timer t2 = new Timer();
    //...
    //codigo de UI
    //...
    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
        segundos.set(parseInt("10"));
        int total = segundos.get() * 1000;
    
        final TimerTask task1 = new TimerTask() {
            @Override
            public void run() {
                //el codigo que modifica el UI DEBE ejecutarse en EDT por tanto se usa 
                //java.awt.EventQueue.invokeAndWait 
                try {
                    java.awt.EventQueue.invokeAndWait(() -> {
                        //implisitamente se llama segundos.toString() que es lo mismo que ""+segundos.get();
                        txtout.setText("   " + segundos);
                        if (segundos.get() == 1) {
                            txtout.setText("Termino!");
                        }
                    });
                } catch (InterruptedException | InvocationTargetException ex) {
                    Logger.getLogger(ButtonPanel.class.getName()).log(Level.SEVERE, null, ex);
                }
                segundos.addAndGet(-1);
            }
        };
        t1.scheduleAtFixedRate(task1, 0, 1000);
    
        TimerTask task2 = new TimerTask() {
            @Override
            public void run() {
                //cancele la TAREA en particular no todas las Tareas
                task1.cancel();
            }
        };
        t2.schedule(task2, total);
    }
    

    However, here is a problem yet! What happens if the user of the app clicks the button many times? it works, but Segundos is restarted to 10 but there is more than 1 task that manipulates Segundos (given that it is atomic it is safe to respect an order of value change or read it ) but does not ensure that the tasks stop at 0 or 1! For example if I make more than 3 clicks on the button after running the text value it shows me:

    in this case a new problem is generated with multiple solutions again:

  • in task1 ensure that when it reaches 1 or 0 the task stops changing the value of segundos
  • auto cancel task1 to reach 1 or 0?
  • add a Lock or Synchronized Variable that indicates if a Task is executing and does not allow Another Task to be registered.
  • Combination of 1 and 3
  • in this case I will apply 4.:

    //variables globales
    AtomicInteger segundos = new AtomicInteger();
    Timer t1 = new Timer();
    Timer t2 = new Timer();
    //nueva variable global: 
    //nos permite saber cuantas Tareas fueron registradas y llevar un control
    //aunque nuestro limite es uno podriamos utilizar un Boolean en lugar de Integer...
    AtomicInteger taskregister = new AtomicInteger();
    //cuantas tareas concurrentes pueden existir? por ahora solo 1 
    final int limiteTareas=1;
    
    //...
    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
        if (taskregister.get() < limiteTareas) {
            segundos.set(parseInt("10"));
            int total = segundos.get() * 1000;
    
            final TimerTask task1 = new TimerTask() {
                @Override
                public void run() {
                    //el codigo que modifica el UI DEBE ejecutarse en EDT por tanto se usa 
                    //java.awt.EventQueue.invokeAndWait 
                    try {
                        java.awt.EventQueue.invokeAndWait(() -> {
                            //implisitamente se llama segundos.toString() que es lo mismo que ""+segundos.get();
                            txtout.setText("   " + segundos);
                            if (segundos.get() == 0) {
                                txtout.setText("termino!");
                            }
                        });
                    } catch (InterruptedException | InvocationTargetException ex) {
                        Logger.getLogger(ButtonPanel.class.getName()).log(Level.SEVERE, null, ex);
                    }
                    //no reste mas cuando llegue a 0
                    if (segundos.get() > 0) {
                        segundos.addAndGet(-1);
                    }
                }
            };
            t1.scheduleAtFixedRate(task1, 0, 1000);
            taskregister.addAndGet(1);
    
            TimerTask task2 = new TimerTask() {
                @Override
                public void run() {
                    task1.cancel();
                    taskregister.addAndGet(-1);
                }
            };
            t2.schedule(task2, total);
        }else{
            System.out.println(String.format("Existen %d de %d tareas Regitradas en transcurso", taskregister.get(),limiteTareas));
        }
    }   
    

    references:

    The Event Dispatch Thread

    Atomic Variables

    Synchronization

        
    answered by 30.12.2018 / 05:57
    source