Search code examples
javaappletrunnablerepaint

Repaint() is not workning out of run() function


I'm trying to make a simple applet with java to show two counters. To simplify the code i created a function named "suma" which is called 2 times in run(). The counters in the console works, but in the applet aren't increased. I thing the problem is in repaint(), because when i try to execute the content of "suma" in run directly the code works. The question is: Why repaint() don't works out of run()?

import java.applet.Applet;
import java.awt.Button;
import java.awt.Color;
import java.awt.Graphics;


public class HiloContador extends Applet implements Runnable{
    //Propiedades
    private Thread h1;
    private Thread h2;
    long contador1=0;
    long contador2=500;
    private Button b1,b2;

    public void start(){}

    public void init(){
        setBackground(Color.YELLOW);
        //Botones
        add(b1=new Button("Parar hilo 1"));
        add(b2=new Button("Parar hilo 2"));
        //Creación de nuevos hilos y su inicio
        h1=new Thread(this);
        h2=new Thread(this);
        h1.start();
        h2.start();
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        suma(h1,contador1);
        suma(h2,contador2);     
    }//fin de run

    public void paint(Graphics g){
        g.drawString(Long.toString((long)contador1), 80, 100);
        g.drawString(Long.toString((long)contador2), 80, 120);
    }

    public void suma(Thread h,long c){
        Thread hiloActual=Thread.currentThread();
        while(h==hiloActual){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(c);
            c++;
            repaint();
        }//fin de while     
    }   
}

enter image description here


Solution

  • This is because when you provide a primitive type like a long to a method, you pass its value not its reference such that when you increment c in your method suma you don't actually modify the value of your variables, you just increment the provided value, use AtomicLong instead of long as parameter of your method since it will then be passed by reference as it is no more a primitive type but an object reference, then increment its internal value with incrementAndGet() and get it with get().

    Your code would then be:

    ...
    AtomicLong contador1 = new AtomicLong();
    AtomicLong contador2 = new AtomicLong(500);
    ...
    
    public void paint(Graphics g){
        g.drawString(Long.toString(contador1.get()), 80, 100);
        g.drawString(Long.toString(contador2.get()), 80, 120);
    }
    
    public void suma(Thread h, AtomicLong c){
        ...
            System.out.println(c);
            c.incrementAndGet();
            repaint();
        ...
    }
    

    More details about pass-by-reference/pass-by-value