How do i run 2 threads at once


DevX Home    Today's Headlines   Articles Archive   Tip Bank   Forums   

Results 1 to 4 of 4

Thread: How do i run 2 threads at once

  1. #1
    Join Date
    Jan 2007
    Posts
    60

    How do i run 2 threads at once

    I am trying to make 2 progress bars, one above the other and the top progress bar moves twice as fast as the bottom progress bar.

    I have got the top progress bar to work properly but I don't know how to get the second on to run at the same time.

    Here is my code

    Code:
    import java.awt.*;
    import java.applet.Applet;
    
    public class Progress extends Applet implements Runnable 
    {   
    	Thread runner;
    	myCanvas ca = new myCanvas();
    	Choice ch = new Choice();
    	Label la;
    	Button a;
    	TextField tf;
    	
    	int xpos;
    	int BarHeight = 30;
    	int BarWidth = 1;
    	
    	public void init() 
    	{
    		setLayout(new GridBagLayout());
            GridBagConstraints c = new GridBagConstraints();
    
    		ch.addItem("IEEE 802.11a");
    		ch.addItem("IEEE 802.11b");
    		ch.addItem("IEEE 802.11g");
    		ch.addItem("IEEE 802.11n");
    		ch.addItem("IHomeRF");
    		c.gridx = 0;
            c.gridy = 0;
            add(ch, c);
    		
    		la = new Label("Enter amount of data (Mbits) to be transferred");
    		c.gridwidth = 2;
    		c.gridx = 1;
    		c.gridy = 0;
    		add(la, c);
    		
    		tf = new TextField("",12);
    		c.gridwidth = 2;
    		c.gridx = 1;
    		c.gridy = 2;
    		add(tf, c);
    	
    		a = new Button("Transfer");
    		c.gridx = 3;
    		c.gridy = 2;
    		add(a, c);
    		
    		ca.setBackground(Color.white);
    		ca.resize(400,150);
    		c.gridwidth = 4;
    		c.gridx = 0;
    		c.gridy = 3;
    		add(ca,c);
    		
    		start();
    	}
    	
    	public void start() 
    	{
    		if(runner==null)
    		{
    			runner= new Thread(this);
    			runner.start();
    		}
    		repaint();
    	}
    	
    	public void run() 
    	{
    	}
    	
    	public class myCanvas extends Canvas 
    	{
    		public void paint(Graphics g) 
    		{
    			g.setColor(Color.black);
    			g.drawString("Theoretical Transfer Speed",0,25);
        		g.drawRect (0, 30, 370, 30);
        		g.drawString("Realistic Transfer Speed",0,85);
        		g.drawRect (0, 90, 370, 30);
        		
        		for(xpos=1; xpos<=369; xpos+=1) 
        		{
        			g.setColor(Color.red);
        			g.fillRect(xpos-1,31,BarWidth,BarHeight);
        			
        			g.setColor(Color.red);
        			g.fillRect(xpos,31,BarWidth,BarHeight);
        			
      				g.setColor(Color.black);
    				g.drawString("Theoretical Transfer Speed",0,25);
        			g.drawRect (0, 30, 370, 30);
        			g.drawString("Realistic Transfer Speed",0,85);
        			g.drawRect (0, 90, 370, 30); 
        			
        			try 
        			{
        				Thread.sleep(500);
        			}
        			catch (InterruptedException e)
        			{	
        			}	 			
        		} 		
    		}
    	}
    }

  2. #2
    Join Date
    Nov 2004
    Location
    Norway
    Posts
    1,560

    Major adjustments required

    There is no use in implementing a runnable w. an empty run() method...

    I have made a fixup of your code here. The idea of a canvas used as a progressbar is ok, but a progressbar shoud not do its own progressing. It should act as a component with only two goals in life; receive the current progress value and repaint itself. Consequently, when you want two progressbars you should instantiate two instances of this class and put them into the applet, and control each one in a separate thread.

    The way you had done it here, by pausing the main thread, froze the whole setup in a tight loop that didn't even give the button, choice or textfield the chance to respond.

    Notice my implementation of the paint job; here paint does nothing but call the update method. The update method is called by the system to refresh the components background. Without this wiring the progressbars are only visible after the execution og the paint method, - and the update method wipes the screen clean. Not what you want I presume .

    There is definitely some additional coding (code reduction) to be done here. Especially regarding the dimensioning of things.

    Here is my fixup:

    Code:
    import java.applet.*;
    import java.awt.*;
    import javax.swing.*;
    
    public class Progress
        extends Applet
        implements Runnable {
      Thread runner1, runner2;
      // ** instantiate two progressbars
      MyProgBar pb1 = new MyProgBar("Theoretical Transfer Speed", 25, new Rectangle(0, 30, 370, 30));
      MyProgBar pb2 = new MyProgBar("Realistic Transfer Speed", 25, new Rectangle(0, 30, 370, 30));
      Choice ch = new Choice();
      Label la;
      Button a;
      TextField tf;
    
      // ** added for testing, applet is used as a Panel (the ancestor of Applet) in a Frame
      public static void main(String[] args) {
        Frame f = new Frame("Test Applet");
        f.setLayout(new GridLayout());
        Progress app = new Progress();
        f.add(app);
        app.init();
        f.setBounds(20, 20, 500, 400);
        f.setVisible(true);
        app.start();
      }
    
      public void init() {
        setLayout(new GridBagLayout());
        GridBagConstraints c = new GridBagConstraints();
    
        ch.addItem("IEEE 802.11a");
        ch.addItem("IEEE 802.11b");
        ch.addItem("IEEE 802.11g");
        ch.addItem("IEEE 802.11n");
        ch.addItem("IHomeRF");
        c.gridx = 0;
        c.gridy = 0;
        add(ch, c);
    
        la = new Label("Enter amount of data (Mbits) to be transferred");
        c.gridwidth = 2;
        c.gridx = 1;
        c.gridy = 0;
        add(la, c);
    
        tf = new TextField("", 12);
        c.gridwidth = 2;
        c.gridx = 1;
        c.gridy = 2;
        add(tf, c);
    
        a = new Button("Transfer");
        c.gridx = 3;
        c.gridy = 2;
        add(a, c);
    
        pb1.setBackground(Color.white);
        pb1.setSize(400, 75);
        c.gridwidth = 4;
        c.gridx = 0;
        c.gridy = 3;
        add(pb1, c);
    
        pb2.setBackground(Color.white);
        pb2.setSize(400, 75);
        c.gridwidth = 4;
        c.gridx = 0;
        c.gridy = 4;
        add(pb2, c);
    
    
    
        start();
      }
    
      /**
       * fire off two threads
       */
      public void start() {
        if (runner1 == null) {
          runner1= new Thread(this);
          runner2= new Thread(this);
          runner1.start();
          runner2.start();
        }
        repaint();
      }
    
      /**
       * tell progressbar(s) to progress, one notch at the time.
       */
      public void run() {
        // act according to the currently running thread
        if (Thread.currentThread()==runner1) {
          for (int xpos = 1; xpos <= 369; xpos += 1) {
            try {
              pb1.setXPos(xpos);
              runner1.sleep(500);
            }
            catch (InterruptedException e) {
              break;
            }
          }
        } else if (Thread.currentThread()==runner2) {
          for (int xpos = 1; xpos <= 369; xpos += 2) {
            try {
              pb2.setXPos(xpos);
              runner2.sleep(500);
            }
            catch (InterruptedException e) {
              break;
            }
          }
    
        }
      }
    
    }
    // i don't like inner classes ...
    class MyProgBar
        extends Canvas {
      int xpos;
      String text=null;
      int yPos=-1;
      Rectangle bounds=null;
    
      public MyProgBar(String text, int yPos, Rectangle bounds) {
        this.text=text;
        this.yPos=yPos;
        this.bounds=bounds;
    
      }
    
      public void setXPos (int xpos) {
        this.xpos=xpos;
        repaint();
      }
    
      public void update (Graphics g) {
        g.setColor(Color.black);
        g.drawString(text, 0, yPos);
        g.drawRect(bounds.x, bounds.y, bounds.width,bounds.height);
        g.setColor(Color.red);
        g.fillRect(0, yPos+6, xpos, 30);
    
      }
      public void paint(Graphics g) {
        update(g);
      }
    }
    Last edited by sjalle; 04-19-2007 at 09:56 PM. Reason: more stuff
    eschew obfuscation

  3. #3
    Join Date
    Jan 2007
    Posts
    60
    Thank you very much sjalle....your help is greatly appreciated as I'm new to trying to do animation using Java.

    I am trying to understand your code and I'm a little lost. I am trying to work out how I set the background to white like you have done but in the progress bars themselves I would like them to be filled in red and when the progress bars move then they turn to green.

    How do I do that? and thank you again for your help.


    BTW the example code I have is what was given to me and I can see it's not very good. I have a book but it's going to take a while to understand it
    Last edited by AdRock; 04-21-2007 at 10:30 AM. Reason: adding something i forgot to mention

  4. #4
    Join Date
    Nov 2004
    Location
    Norway
    Posts
    1,560

    Here is a more complete solution

    I have done four major changes/additions in the setup, in addition to what you requested.

    The progressbars are not supplied a text. They should be progressbars and
    nothing more, and the text for them are supplied in separate labels. Having to mess around with the text positioning/size inside the same component that draws the bars is messy and complicates things.

    The GridbagLayout is great stuff but for simplicity I have used no layoutmanager and only used the components' setBounds(x,y,w,h) method for positioning them.

    I have used double buffering for the progressbars. Check the code. If you want to do animations there is no way around double buffering (unless you prefer garbage and flickering on the screen).

    I have made the applet an actionlistener in order to respond to the buttonclicks, so this setup starts and stop the progessing. Note: you have to press "Transfer" in order to start the stuff.

    I realize that I have given you quite a bit to chew on here, but when you fully understand what this code block does you have made a great step towards becoming a true java programmer.

    NOTE: The setup here enables you to test the applet as a local application, - no browser required (the main(..) method that facilitates this is never executed by the browser, so you don't have to remove it when you deploy the applet on the web).
    However, when you run threads in an applet they will continue to run (if not stopped) after the client leaves the web page with the applet. That is bad practise. Therefore you must also implement the applet's stop() method. This method is called by by the browser when the client leaves the page to inform the applet that it should stop its execution. I will leave it to you to quess what this method should do.

    Enjoy

    Code:
    import java.applet.*;
    import java.awt.*;
    import javax.swing.*;
    import java.awt.image.*;
    import java.awt.event.*;
    
    public class Progress extends Applet implements Runnable, ActionListener  {
      Thread runner1, runner2;
      boolean running=false; // stop flag for threads
      MyProgBar pb1 = new MyProgBar();  // instantiate two progressbars
      MyProgBar pb2 = new MyProgBar();
      Choice ch = new Choice();
      Button transferBtn=new Button("Transfer");
      TextField amountTF=new TextField();
    
      // ** added for testing, applet is used as a Panel (the ancestor of Applet) in a Frame
      public static void main(String[] args) {
        Frame f = new Frame("Test Applet");
        f.setLayout(new GridLayout());
        Progress app = new Progress();
        f.add(app);
        app.init();
        f.setBounds(20, 20, 500, 400);
        f.setVisible(true);
        app.start();
      }
      /**
       * Methods for set/get of running flag.
       * synchronized ensures that no two (or more) threads can invoke any
       * of these methods at "the same time".  Of course, two threads never 
       * run at the same time, but the VM may halt the execution of a 
       * thread "inside" a method and give the control to another thread, and
       * that may cause problems.  So "synchronized" ensures that a thread  
       * that is processing a synchronized method is allowed to finish the method
       * before another thread is allowed to invoke it.
       */
      private synchronized void setRunning(boolean run) {
        this.running=run;
        // tell the progressbars what has happened
        pb1.setProgressing(run);
        pb2.setProgressing(run);
        // then make sure they show it
        pb1.repaint();
        pb2.repaint();
        if (!run) // runner1's value is used as indicator...
          runner1=null;
      }
      private synchronized boolean isRunning() {
        return running;
      }
      /**
       * Handle buttonclicks.  Change the button label according to the
       * current program state.
       * @param ae
       */
      public void actionPerformed (ActionEvent ae) {
        String txt=ae.getActionCommand(); // get button text
        if (txt.equals("Transfer")) {
          startRunning();
          transferBtn.setLabel("Stop");
        } else if (txt.equals("Stop")) {
          setRunning(false);
          transferBtn.setLabel("Transfer");
        }
      }
      /**
       * Initiate the GUI, using XY-layout (no layoutmanager)
       */
      public void init() {
        setLayout(null);
    
        makeChoice();
    
        ch.setBounds(10,10,100,22);
        add(ch);
    
        Label la1 = new Label("Enter amount of data (Mbits) to be transferred");
        la1.setBounds(10,40,260,22);
        add(la1);
    
        amountTF.setBounds(10,70,100,22);
        add(amountTF);
    
        transferBtn.setBounds(125,70,70,22);
        add(transferBtn);
    
        Label la2=new Label("Theoretical transfer rate");
        la2.setBounds(10,100,150,22);
        add(la2);
    
        pb1.setBounds(10,130,250,22);
        add(pb1);
    
        Label la3=new Label("Realistic transfer rate");
        la3.setBounds(10,160,150,22);
        add(la3);
    
        pb2.setBounds(10,190,250,22);
        add(pb2);
    
        transferBtn.addActionListener(this); // hook up the button
    
        start();
      }
      /**
       * Set up the choice component
       */
      private void makeChoice() {
        ch.addItem("IEEE 802.11a");
        ch.addItem("IEEE 802.11b");
        ch.addItem("IEEE 802.11g");
        ch.addItem("IEEE 802.11n");
        ch.addItem("IHomeRF");
      }
      /**
      * fire off two threads
      */
      private void startRunning() {
        if (runner1 == null) {
          runner1= new Thread(this);
          runner2= new Thread(this);
          setRunning(true);
          runner1.start();
          runner2.start();
        }
        repaint();
      }
    
      public void start() {}
    
      /**
       * tell progressbar(s) to progress, one notch at the time.
       */
      public void run() {
        // act according to the currently running thread
        if (Thread.currentThread()==runner1) {
          for (int val = 1; val <= 369 && isRunning(); val++) {
            try {
              pb1.setProgressValue(val);
              runner1.sleep(500);
            }
            catch (InterruptedException e) {
              break;
            }
          }
        } else if (Thread.currentThread()==runner2) {
          for (int val = 1; val <= 369 && isRunning(); val += 2) {
            try {
              pb2.setProgressValue(val);
              runner2.sleep(500);
            }
            catch (InterruptedException e) {
              break;
            }
          }
    
        }
      }
    
    }
    /**
     * The progressBar Class, implemented w. double buffering.
     * double buffering: If the system performs a screen refresh during the paint job
     * then the paint job is unfinished and the display will flicker.  To avoid this
     * an image is created in memory and the paint job draws on that image.  The last
     * operation of the paint job is then to draw that image on the display's graphical
     * context.  That draw operation is _very_ fast and you get a smooth
     * animation on the screen.  In fact, animation without double buffering is a mess,
     */
    class MyProgBar extends Canvas {
    
      int progValue=-1;
      BufferedImage memImg=null; // the memory image
      Graphics memG=null; // the memory image's graphical context.
      private boolean progressing=false;
    
      /**
       * Empty constructor
       */
      public MyProgBar() {}
    
      /**
       * Create the buffered image and get its graphics context for drawing into.
       */
      private void prepareDoubleBuffering() {
        memImg=new BufferedImage(getWidth(),getHeight(),BufferedImage.TYPE_INT_RGB);
        memG=memImg.getGraphics();
      }
    
      /**
       * Set current progressbar value
       * @param progValue
       */
      public void setProgressValue (int progValue) {
        this.progValue=progValue;
    
        repaint();
      }
      public void setProgressing (boolean progressing) {
        this.progressing=progressing;
      }
      /**
       * Fills backround w. specified color
       * It is a good practice to save the graphics context's current (default) color
       * in each method that sets other color(s), an restore it before return.
       * @param g : a graphics context
       * @param c
       */
      private void fillBackground (Graphics g, Color c) {
        Color dfltColor=g.getColor(); // save default color
        g.setColor(c); // set background color
        g.fillRect(0,0,getWidth(),getHeight()); // fill the canvas with the color
        g.setColor(dfltColor); // restore default color
      }
    
      /**
       * @param g : the displays graphical context
       */
      public void update (Graphics g) {
        /**
         * The dimensioning of the buffered image is depending on the size of the
         * canvas.  So we have to create it here, since invocation of this method
         * only occurs when the component is displayed, - i.e. has a size.  If we had
         * done this in the constructor the size would have been 0,0
         */
        if (memG==null) { // is only true first time around
          prepareDoubleBuffering();
        }
        // work only on the memory buffer
        if (progressing)
          fillBackground(memG, Color.green);
        else
          fillBackground(memG, Color.white);
        memG.setColor(Color.red);
        memG.fillRect(0, 0, progValue, getHeight());
        memG.setColor(Color.black);
        memG.drawRect(0,0, getWidth()-1,getHeight()-1);
    
        // transfer the memory image to  the display context
        g.drawImage(memImg,0,0,this);
      }
    
      /**
       * @param g : the displays graphical context
       */
      public void paint(Graphics g) {
        update(g);
      }
    }
    PS: I guess you realize that a progressbar need more flesh on the bone. Like a min and max value so that it can calibrate itself. As it is now there is no telling whether the progression stops at the far right of the canvas, or before or after...
    Last edited by sjalle; 04-22-2007 at 07:21 AM. Reason: Note about the stop() method
    eschew obfuscation

Similar Threads

  1. Batch file to run a list of .sql files
    By Ben in forum Database
    Replies: 7
    Last Post: 11-19-2008, 08:48 AM
  2. Please help with threads
    By cookie in forum Java
    Replies: 6
    Last Post: 03-15-2006, 08:06 AM
  3. running large number of java threads
    By letianrong in forum Java
    Replies: 3
    Last Post: 09-19-2005, 06:37 AM
  4. Replies: 1
    Last Post: 12-10-2000, 03:59 PM
  5. Replies: 0
    Last Post: 09-26-2000, 10:52 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
HTML5 Development Center
 
 
FAQ
Latest Articles
Java
.NET
XML
Database
Enterprise
Questions? Contact us.
C++
Web Development
Wireless
Latest Tips
Open Source


   Development Centers

   -- Android Development Center
   -- Cloud Development Project Center
   -- HTML5 Development Center
   -- Windows Mobile Development Center