Hot questions for Using Applets in multithreading

Top Java Programmings / Applets / multithreading

Question:

i've got a problem with what should be a simple excercise. I've been asked to make an applet that prints a green oval (filled) that becomes larger until it hits the borders, than start becoming smaller. This should go on until you close the applet.

Well, i came out with this code

import java.awt.Color;
import java.awt.Graphics;

import javax.swing.JApplet;

public class Disco extends JApplet{

private int x;
private int y;
private int r;
private boolean enlarge;
MakeLarger makeLarger;
MakeSmaller makeSmaller;

public void init() {}

public void start() {
    x = getWidth()/2;
    y = getHeight()/2;
    r = 50;
    enlarge = true;
    makeLarger = new MakeLarger();
    makeLarger.start();
}

public void paint(Graphics g) {
    g.setColor(Color.GREEN);
    g.fillOval(x - r, y- r, r*2, r*2);
}

public void update() {
    if(enlarge) {
        makeLarger = new MakeLarger();
        makeLarger.start();
    } else {
        makeSmaller = new MakeSmaller();
        makeSmaller.start();
    }
}


private class MakeLarger extends Thread {

    public void run()  {
        while(true) {
            x = getWidth()/2;
            y = getHeight()/2;

            if(getWidth() > getHeight()) {
                if(r < getHeight()/2) {
                    r++;
                    repaint();
                    try {
                    sleep(25);
                    } catch(InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    enlarge = false;
                    update();
                    Thread.currentThread().interrupt();
                    return;
                }
            } else {
                if(r < getWidth()/2) {
                    r++;
                    repaint();
                    try {
                        sleep(25);
                        } catch(InterruptedException e) {
                            e.printStackTrace();
                        }
                }   else {
                    enlarge = false;
                    update();
                    Thread.currentThread().interrupt();
                    return;
                }
            }
        }
    }

}
private class MakeSmaller extends Thread {

    public void run()  {
        while(true) {
            x = getWidth()/2;
            y = getHeight()/2;

                if(r > 50) {
                    r--;
                    repaint();
                    revalidate();
                    try {
                    sleep(25);
                    } catch(InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    enlarge = true;
                    update();
                    Thread.currentThread().interrupt();
                    return;
                }
            }

      }

  }
}

When I start my applet the oval start growing correctly until it hits the border and then suddently stop.

The first thing i thought was that it wasn't getting smaller correctly. But a little System.out.println work showed me that all computation was going on correctly, the problem is that the applet repaint only while the makeLarger thread is active, when the makeSmaller thread is at work the call to repaint() doesn't work! If i resize the applet window while the makeSmaller Thread is at work it repaints correctly showing me the oval getting smaller.

Can, please, someone enlight me on this odd behavior? What am I missing?

thank you everyone for your most appreciated help and sorry if my english is so poor!


Answer:

I can't say that I've looked at all the code, but a couple of suggestions:

  • Paint in a JPanel's paintComponent override.
  • This is key: call the super.paintComponent method in the override, first line. This gets rid of prior images so that the image can get smaller.
  • Display the JPanel within your JApplet by adding it to the applet.
  • Myself, I'd use a single Swing Timer for the animation loop, and would use a boolean to decide which direction the sizing should go.
  • But regardless of whether I were using a Swing Timer or a Runnable placed in a Thread, I'd try to keep things a simple as possible, and that would mean using a single Timer that changes direction of resizing or a single Runnable/Thread that changes size of resizing based on a boolean. This swapping of threads that you're doing just serves to overly and unnecessarily complicate things, and could quite possibly be the source of your error.
  • As a side recommendation, you almost never want to extend Thread. Much better is to create classes that implement Runnable, and then when you need to run them in a background thread, create a Thread, passing in your Runnable into the Thread's constructor, and then calling start() on the Thread.

Question:

Hey I'm trying to have the console print out "holding" when a key is being held. I'm using an applet because this code is to test key holding in applets. if any someone with good java knowledge can explain to me whats going on it will be much appreciated.

I'm pretty sure that the problem might have something to do with the thread.

public class appletkeytest extends Applet implements KeyListener, Runnable {

    boolean held;

    public void init(){
        addKeyListener(this);
        Thread t = new Thread( this );
        t.start();
    }

    public void keyTyped(KeyEvent e) {
    }

    public void keyPressed(KeyEvent e) {
        held = true;
        System.out.println(held);
    }

    public void keyReleased(KeyEvent e) {   
        held = false;
        System.out.println(held);
    }

    public void run() {
        System.out.println(held);

        while(held){
            System.out.println("holding");
        }   
    }
}

Answer:

First, I'd advise defining held as volatile.

Second, since you start the thread from the init() method, it will start running before you ever pressed the key, and thus finish right away.

I'd leave init like this:

public void init() {
    addKeyListener(this);
}

And change the keyPressed listener to:

public void keyPressed(KeyEvent e) {
    boolean wasHeld = held;
    held = true;
    System.out.println(held);
    if ( !wasHeld) {
        Thread t = new Thread(this);
        t.start();
    }
}

The reasoning behind the wasHeld variable is that when you hold down a key, it actually sends multiple keyPressed events until it is released. If you just created a thread for each of these, you'll have many threads created during one key holding, all of them busily writing to your console.

So you want to create the thread only if this is the first time the keyPressed event was sent for this particular key press. A new thread will be created when you press a key again after releasing the previous one.

Question:

I want to fill an applet with blue color. I am doing this using paint(Graphics g) method. While filling the applet, i get StackOverFlowException after 8-10 seconds. I want to get rid of it. Please suggest me what to do or correct me if i am doing wrong. I asked someone about this, he said it store locations and removing them later, so that stack is always nearly empty. Please help me.

Code:

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

public class Flooding extends Applet
{
    boolean[][] mark;
    boolean justOnce = true;

    @Override
    public void init()
    {
        mark = new boolean[800][600];

        this.setSize(100, 500);
        this.setPreferredSize(new Dimension(100, 500));
        this.setVisible(true);
    }

    @Override
    public void start()
    {
        setBackground(Color.WHITE);
        setForeground(Color.BLACK);
    }

    @Override
    public void paint(Graphics g)
    {
        if(justOnce)
        {
            super.paint(g);
            justOnce = false;
        }

        for (int row=0; row<500; row++)
        {
            for (int col=0; col<100; col++) 
            {
                flood(mark, row, col, g);
            }
        }
    }

    private static void sleep(int msec)
    {
        try 
        {
            Thread.currentThread().sleep(msec);
        }
        catch (InterruptedException e) { }
    }

    public void flood( boolean[][] mark, int row, int col, Graphics g)
    {
        if (row < 0) return;
        if (col < 0) return;
        if (row > 100) return;
        if (col > 500) return;

        if (mark[row][col]) return;

        g.setColor(Color.BLUE);
        g.drawLine(row, col, row, col);

        mark[row][col] = true;

        repaint();
        sleep(1);

        flood(mark, row - 1, col, g);
        flood(mark, row, col, g);
        flood(mark, row + 1, col, g);
        flood(mark, row-1, col-1, g);
        flood(mark, row, col-1, g);
        flood(mark, row+1, col-1, g);
        flood(mark, row-1, col + 1, g);
        flood(mark, row, col + 1, g);
        flood(mark, row+1, col + 1, g);
    }
}

Answer:

Look at your code: first call to flood() is with coordinates (0, 0) which later calls flood() with coordinates (1, 0) which calls flood()... With your dimensions, you get to a recursion 500 levels deep. Change your code to not using recursion.

(You can of course increase the stack size with -Xss, but your code is broken, so fix that instead.)

Question:

So I am currently learning Java applets and have this code that involves an Applet and a Thread in order to make an applet scroll a message string using repaint() method.

import java.awt.*;
import java.applet.*;

/*
<applet code="Banner" width=300 height=50>
</applet>
*/

public class Banner extends Applet implements Runnable
{
    String msg = " Java Rules the Web ";
    Thread t;
    boolean stopFlag;

    public void init()
    {
        t = null;
    }

    public void start()
    {
        t = new Thread(this);
        stopFlag = false;
        t.start();
    }

    public void run()
    {
        for(;;)
        {
            try
            {
                repaint();
                Thread.sleep(250);
                if(stopFlag)
                    break;
            }
            catch(InterruptedException exc)
            {

            }
        }
    }

    public void stop()
    {
        stopFlag = true;
        t = null;
    }

    public void paint(Graphics g)
    {
char ch;
    ch = msg.charAt(0);
        msg = msg.substring(1, msg.length());
        msg += ch;
        g.drawString(msg,50,30);
    }
}

So the problem is that I dont understand why init initialize Thread in null, when does start method is called and when init method is called, also when does the stop method is called in order to set stopFlag to false and how does this final part make the String to scroll:

public void paint(Graphics g)
    {
char ch;
    ch = msg.charAt(0);
        msg = msg.substring(1, msg.length());
        msg += ch;
        g.drawString(msg,50,30);
    }
}

Thanks


Answer:

The applet container calls init when it creates the applet, start when it makes the applet visible, and stop when the applet goes away (like you leave the page hosting the applet). Setting the t field to null in the init method doesn't do anything, since it will be null when the object is created anyway. The message is scrolled by taking a character from the start of the string and putting it at the end of the string, then re-displaying the string in the applet window. The thread does this every 250 ms until the applet is stopped.

Applets are a dead technology.

Question:

I have this applet here that I have to make it work in multithreads. I try to, but its seems when set the number of threads at 1, the program runs as expected. So, generally the program runs ok. But if I set the value lets say 2 or 4. Is getting crazy. Im not getting the required outcome. It seems that is something wrong with the calculations. Im banging my head on the wall, trying to figure out whats wrong but, everything I tried, seems to not solve the problem. Heres is the sequential code:

/*
 * "Physics" part of code adapted from Dan Schroeder's applet at:
 *
 *     http://physics.weber.edu/schroeder/software/mdapplet.html
 */

import java.awt.* ;
import javax.swing.* ;

public class MD {

    // Size of simulation

    final static int N = 2000 ;   // Number of "atoms"
    final static double BOX_WIDTH = 100.0 ;


    // Initial state - controls temperature of system

    //final static double VELOCITY = 3.0 ;  // gaseous
    final static double VELOCITY = 2.0 ;  // gaseous/"liquid"
    //final static double VELOCITY = 1.0 ;  // "crystalline"

    final static double INIT_SEPARATION = 2.2 ;  // in atomic radii


    // Simulation

    final static double DT = 0.01 ;  // Time step


    // Display

    final static int WINDOW_SIZE = 800 ;
    final static int DELAY = 0 ;
    final static int OUTPUT_FREQ = 20 ;


    // Physics constants

    final static double ATOM_RADIUS = 0.5 ;

    final static double WALL_STIFFNESS = 500.0 ;
    final static double GRAVITY = 0.005 ;
    final static double FORCE_CUTOFF = 3.0 ;


    // Atom positions
    static double [] x = new double [N] ;
    static double [] y = new double [N] ;

    // Atom velocities
    static double [] vx = new double [N] ;
    static double [] vy = new double [N] ;

    // Atom accelerations
    static double [] ax = new double [N] ;
    static double [] ay = new double [N] ;


    public static void main(String args []) throws Exception {

        Display display = new Display() ;

        // Define initial state of atoms

        int sqrtN = (int) (Math.sqrt((double) N) + 0.5) ;
        double initSeparation = INIT_SEPARATION * ATOM_RADIUS ;
        for(int i = 0 ; i < N ; i++) {
            // lay out atoms regularly, so no overlap
            x [i] = (0.5 + i % sqrtN) * initSeparation ;
            y [i] = (0.5 + i / sqrtN) * initSeparation ;
            vx [i] = (2 * Math.random() - 1) * VELOCITY ;
            vy [i] = (2 * Math.random() - 1) * VELOCITY ;
        } 

        int iter = 0 ;
        while(true) {

            if(iter % OUTPUT_FREQ == 0) {
                System.out.println("iter = " + iter + ", time = " + iter * DT) ;
                display.repaint() ;
                Thread.sleep(DELAY) ;
            }

            // Verlet integration:
            // http://en.wikipedia.org/wiki/Verlet_integration#Velocity_Verlet

            double dtOver2 = 0.5 * DT;
            double dtSquaredOver2 = 0.5 * DT * DT;
            for (int i = 0; i < N; i++) {
                x[i] += (vx[i] * DT) + (ax[i] * dtSquaredOver2);
                        // update position
                y[i] += (vy[i] * DT) + (ay[i] * dtSquaredOver2);
                vx[i] += (ax[i] * dtOver2);  // update velocity halfway
                vy[i] += (ay[i] * dtOver2);
            }

            computeAccelerations();

            for (int i = 0; i < N; i++) {
                vx[i] += (ax[i] * dtOver2);
                        // finish updating velocity with new acceleration
                vy[i] += (ay[i] * dtOver2);
            }

            iter++ ;
        }
    }

    // Compute accelerations of all atoms from current positions:
    static void computeAccelerations() {

        double dx, dy;  // separations in x and y directions
        double dx2, dy2, rSquared, rSquaredInv, attract, repel, fOverR, fx, fy;

        // first check for bounces off walls, and include gravity (if any):
        for (int i = 0; i < N; i++) {
            if (x[i] < ATOM_RADIUS) {
                ax[i] = WALL_STIFFNESS * (ATOM_RADIUS - x[i]);
            }
            else if (x[i] > (BOX_WIDTH - ATOM_RADIUS)) {
                ax[i] = WALL_STIFFNESS * (BOX_WIDTH - ATOM_RADIUS - x[i]);
            }
            else {
                ax[i] = 0.0;
            }
            if (y[i] < ATOM_RADIUS) {
                ay[i] = (WALL_STIFFNESS * (ATOM_RADIUS - y[i]));
            }
            else if (y[i] > (BOX_WIDTH - ATOM_RADIUS)) {
                ay[i] = (WALL_STIFFNESS * (BOX_WIDTH - ATOM_RADIUS - y[i]));
            }
            else {
                ay[i] = 0;
            }
            ay[i] -= GRAVITY ;
        }

        double forceCutoff2 = FORCE_CUTOFF * FORCE_CUTOFF ;

        // Now compute interaction forces (Lennard-Jones potential).
        // This is where the program spends most of its time.


        for (int i = 1; i < N; i++) {
            for (int j = 0; j < i; j++) {           // loop over all distinct pairs
                dx = x[i] - x[j];
                dx2 = dx * dx;
                if (dx2 < forceCutoff2) {               // make sure they're close enough to bother
                    dy = y[i] - y[j];
                    dy2 = dy * dy;
                    if (dy2 < forceCutoff2) {
                        rSquared = dx2 + dy2;
                        if (rSquared < forceCutoff2) {
                            rSquaredInv = 1.0 / rSquared;
                            attract = rSquaredInv * rSquaredInv * rSquaredInv;
                            repel = attract * attract;
                            fOverR = 24.0 * ((2.0 * repel) - attract) * rSquaredInv;
                            fx = fOverR * dx;
                            fy = fOverR * dy;
                            ax[i] += fx;  // add this force on to i's acceleration (mass = 1)
                            ay[i] += fy;

                            ax[j] -= fx;  // Newton's 3rd law
                            ay[j] -= fy;
                        }
                    }
                }
            }
        }
    }


    static class Display extends JPanel {

        static final double SCALE = WINDOW_SIZE / BOX_WIDTH ;

        static final int DIAMETER =
                Math.max((int) (SCALE * 2 * ATOM_RADIUS), 2) ;

        Display() {

            setPreferredSize(new Dimension(WINDOW_SIZE, WINDOW_SIZE)) ;

            JFrame frame = new JFrame("MD");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setContentPane(this);
            frame.pack();
            frame.setVisible(true);
        }

        public void paintComponent(Graphics g) {
            g.setColor(Color.WHITE) ;
            g.fillRect(0, 0, WINDOW_SIZE, WINDOW_SIZE) ;
            g.setColor(Color.BLUE) ;
            for(int i = 0 ; i < N ; i++) {
                g.fillOval((int) (SCALE * (x [i] - ATOM_RADIUS)),
                           WINDOW_SIZE - 1 - (int) (SCALE * (y [i] + ATOM_RADIUS)),
                           DIAMETER, DIAMETER) ;
            } 
        }
    }
}

Can anybody spot whats the problem?


Answer:

begin and end are declared as static so all the threads are wrongly using the same variables during their computation.

A) The begin/end will be mistakenly set to some random output of the race conditions between the threads at the begining of their method run()

B) All threads will potentially work on the same indexes range ignoring rest of the position, velocity, acceleration arrays.

Also all threads are running uncessary exactly the same code:

           for (int i = 0; i < N; i++) {
                x[i] += (vx[i] * DT) + (ax[i] * dtSquaredOver2);
                // update position
            ...

I would recommend changing all the variables to instance variables, and then going through the code modified to static only those which should be shared between the threads. Reads of the static variable are fine, the writes have to be checked if they are exclusive. (Writing to different parts of your x, vx... arrays are 'exclusive' in that sense, just make sure that indexes do not overlap).