Do I need Threads for this?

Discussion in 'Java' started by Guest, Dec 5, 2006.

  1. Guest

    Guest Guest

    I've got a method that copies files from one place to another. Each time the
    file copies over it takes roughly 10 seconds per file (depending on how
    large the file is).

    In the meantime, I need my JPanel label to update with the current number of
    files copied over so far.

    I know from looking at the FAQs for this newsgroup that the GUI isn't
    updating because it probably needs a new thread, but as a complete newbie to
    threads, I'm wondering if I really need to learn about Threads to get my
    relatively simple job done. My code simply runs in a for loop -

    int count=0;

    for (int i=0; i < 12; i++) {

    mycopyOverFileMethod();
    count++;
    label.setText("Files Copied:" + count);

    // Why is there no simple way in java just to put here something like :
    // label.redraw();
    // that avoids the need for threads??

    }

    Is there something simple I could do?

    TIA
     
    Guest, Dec 5, 2006
    #1
    1. Advertising

  2. Guest

    Guest

    lid wrote:
    > I've got a method that copies files from one place to another. Each time the
    > file copies over it takes roughly 10 seconds per file (depending on how
    > large the file is).
    >
    > In the meantime, I need my JPanel label to update with the current number of
    > files copied over so far.


    Yes, you need threads, but it's not that hard. You make a class that
    implements Runnable or extends Thread. Then you can do all ten files
    at once, if you choose to!

    --Dale--
     
    , Dec 5, 2006
    #2
    1. Advertising

  3. Guest

    Oliver Wong Guest

    <> wrote in message
    news:...
    > lid wrote:
    >> I've got a method that copies files from one place to another. Each time
    >> the
    >> file copies over it takes roughly 10 seconds per file (depending on how
    >> large the file is).
    >>
    >> In the meantime, I need my JPanel label to update with the current number
    >> of
    >> files copied over so far.

    >
    > Yes, you need threads, but it's not that hard. You make a class that
    > implements Runnable or extends Thread. Then you can do all ten files
    > at once, if you choose to!


    It's not super hard, but it's not super easy either. This tutorial
    should get you started:
    http://java.sun.com/docs/books/tutorial/essential/concurrency/

    - Oliver
     
    Oliver Wong, Dec 5, 2006
    #3
  4. Guest

    Guest Guest

    > Yes, you need threads, but it's not that hard. You make a class that
    > implements Runnable or extends Thread. Then you can do all ten files
    > at once, if you choose to!


    Hmm, seems a bit awkward, but then Java seems that way sometimes...

    Methodically, I can't understand how by splitting the work into two threads
    its going to update the label at the time I need it to - won't it just split
    into two and one process copy over the files in one thread all at once and
    update the labels all at once in the other, meaning that there won't be any
    real live interaction between the two? I guess I'm really saying that I
    don't understand how the thread processes interact with each other...
     
    Guest, Dec 5, 2006
    #4
  5. Guest

    Oliver Wong Guest

    <> wrote in message
    news:...
    >> Yes, you need threads, but it's not that hard. You make a class that
    >> implements Runnable or extends Thread. Then you can do all ten files
    >> at once, if you choose to!

    >
    > Hmm, seems a bit awkward, but then Java seems that way sometimes...
    >
    > Methodically, I can't understand how by splitting the work into two
    > threads its going to update the label at the time I need it to - won't it
    > just split into two and one process copy over the files in one thread all
    > at once and update the labels all at once in the other, meaning that there
    > won't be any real live interaction between the two? I guess I'm really
    > saying that I don't understand how the thread processes interact with each
    > other...


    Presumably the thread which is doing the file-copying will update some
    region in memory, recording it's progress. E.g. "Okay, I'm done with file
    #4... now I'm done with #5... #6...", periodically releasing the CPU
    (actually, once it tells the HD to start copying, it can immediately release
    the CPU, because it has to wait for the HD to actually perform the reads and
    the writes, only to be notified when the copy has finished, to schedule more
    copies, and go back to sleep).

    Meanwhile, the main thread will be scanning this region of memory and
    see "Okay, so that thread is done with file #6. That means I need to change
    the label to say 'Files copied: 6', and then release the CPU so that the
    implicit thread that AWT/Swing creates has a chance to actually draw the
    changes I've made to screen."

    - Oliver
     
    Oliver Wong, Dec 5, 2006
    #5
  6. Guest

    Guest Guest

    > Presumably the thread which is doing the file-copying will update some
    > region in memory, recording it's progress. E.g. "Okay, I'm done with file
    > #4... now I'm done with #5... #6...", periodically releasing the CPU


    Well yes - as in my original code -

    mycopyOverFileMethod();
    count++;
    label.setText("Files Copied:" + count);

    - this copies the file, when that's done, surely, the thread continues onto
    count++ (recording in memory where its got to) and then sets the label.

    Why does my label not update before going back around in the for loop to do
    another file copy? Surely the processor is freed up to do the lines after
    the mycopyOverFileMethod() before doing this method again? That's why I'm
    confused!
     
    Guest, Dec 5, 2006
    #6
  7. Guest

    Colin Miller Guest

    Try calling label.repaint(); after you set the text. Or if you're using
    say a JFrame, try calling the JFrame's repaint(); method.

    It's possible that even though you updated the component, it was never
    painted to the screen.

    ~Colin

    lid wrote:
    > > Presumably the thread which is doing the file-copying will update some
    > > region in memory, recording it's progress. E.g. "Okay, I'm done with file
    > > #4... now I'm done with #5... #6...", periodically releasing the CPU

    >
    > Well yes - as in my original code -
    >
    > mycopyOverFileMethod();
    > count++;
    > label.setText("Files Copied:" + count);
    >
    > - this copies the file, when that's done, surely, the thread continues onto
    > count++ (recording in memory where its got to) and then sets the label.
    >
    > Why does my label not update before going back around in the for loop to do
    > another file copy? Surely the processor is freed up to do the lines after
    > the mycopyOverFileMethod() before doing this method again? That's why I'm
    > confused!
     
    Colin Miller, Dec 5, 2006
    #7
  8. Guest

    Guest Guest

    > Try calling label.repaint(); after you set the text. Or if you're using
    > say a JFrame, try calling the JFrame's repaint(); method.
    >
    > It's possible that even though you updated the component, it was never
    > painted to the screen.


    Thanks for the suggestions - I'd already tried that - it just doesn't update
    until the for loop gets to the end then it updates the label and obviously
    not as intended (ie only updates it with the finishing number rather than
    updating it with the current number as it goes along)

    : (
     
    Guest, Dec 5, 2006
    #8
  9. Guest

    Colin Miller Guest

    Ok, how about this. Create a new class of type Runnable (You'll need
    to read up a bit on threading on this, and it's good to know anyway).
    Inside of that class is where you will do your file copying. Also in
    that class, have a variable to store whatever class holds your JPanel.
    When creating an instance of this new class, pass it a reference to
    that class for callback.

    In your main class, or wherever you initiate the file copying, create
    an instance of this new class and pass it "this" and set it to run. In
    the class that does the file copying, after you finish copying a file,
    you'll call a callback method to do the form update. Unfortunately, I'm
    bad at explaining it.. I'll put some psudocode for you.

    //Main Class
    //Note: This will probably look different

    public class MainClass {
    public static void main(String[] args) {
    JFrame = new JFrame();
    /* ... all your other components and whatever you do to set your
    screen */
    }

    public void buttonClick(Event e) {
    //I'll assume you start file copying on a button click or something
    FileCopying fc = new FileCopying();
    fc.setCallback(this);
    new Thread(fc).start();
    }

    public void updateCopies(int copies) {
    label.setText("Files copied: " + copies);
    }
    }

    //FileCopying class
    public class FileCopying implements Runnable {
    private MainClass callback;
    /* whatever else you need for copying */

    public void setCallback(MainClass cb) {
    callback = cb;
    }

    public void run() {
    for (int i=0; i < filesToBeCopied; i++) {
    /* do your file copying here */
    callback.updateCopies(i);
    }
    }
    }


    I hope that made some sense.. been a while since I did graphical work
    and threads and all of that, but should help with some ideas hopefully.

    ~Colin


    lid wrote:
    > > Try calling label.repaint(); after you set the text. Or if you're using
    > > say a JFrame, try calling the JFrame's repaint(); method.
    > >
    > > It's possible that even though you updated the component, it was never
    > > painted to the screen.

    >
    > Thanks for the suggestions - I'd already tried that - it just doesn't update
    > until the for loop gets to the end then it updates the label and obviously
    > not as intended (ie only updates it with the finishing number rather than
    > updating it with the current number as it goes along)
    >
    > : (
     
    Colin Miller, Dec 5, 2006
    #9
  10. Guest

    Guest

    Oliver Wong wrote:
    > <> wrote in message
    > news:...
    > >> Yes, you need threads, but it's not that hard. You make a class that
    > >> implements Runnable or extends Thread. Then you can do all ten files
    > >> at once, if you choose to!

    > >
    > > Hmm, seems a bit awkward, but then Java seems that way sometimes...
    > >

    snip
    > > saying that I don't understand how the thread processes interact with each
    > > other...

    >
    > Presumably the thread which is doing the file-copying will update some
    > region in memory, recording it's progress.


    Yeah, sorta, but when I think about doing things in Java, I try not to
    think of memory regions. The idea has already been expressed above:
    You pass a reference of "yourself" (ie "this") to the thread doing the
    copy. Then you can do lots of stuff, like call a method in "yourself"
    from the spun-off thread. And/or you can use "join" that waits for all
    of your threads to complete. I didn't look at that example link, but I
    imagine that would be a really good way to start (that is, unless
    someone more energetic than I writes you a snippet or two... it really
    wouldn't be many lines of code... like 15 maybe).

    --Dale--

    --Dale--
     
    , Dec 5, 2006
    #10
  11. Guest

    Oliver Wong Guest

    <> wrote in message
    news:...
    >> Presumably the thread which is doing the file-copying will update some
    >> region in memory, recording it's progress. E.g. "Okay, I'm done with file
    >> #4... now I'm done with #5... #6...", periodically releasing the CPU

    >
    > Well yes - as in my original code -
    >
    > mycopyOverFileMethod();
    > count++;
    > label.setText("Files Copied:" + count);
    >
    > - this copies the file, when that's done, surely, the thread continues
    > onto count++ (recording in memory where its got to) and then sets the
    > label.
    >
    > Why does my label not update before going back around in the for loop to
    > do another file copy? Surely the processor is freed up to do the lines
    > after the mycopyOverFileMethod() before doing this method again? That's
    > why I'm confused!


    I'm guessing your code is running in the EDT, the Event Dispatch Thread,
    which AWT/Swing implicitly creates for you as soon as you use them for GUIs.

    Because your code is running in the EDT, the EDT is not free to do other
    stuff, like actually take the changes caused by label.setText(), and render
    them onto the screen.

    - Oliver
     
    Oliver Wong, Dec 5, 2006
    #11
  12. Guest

    Wesley Hall Guest

    lid wrote:
    > I've got a method that copies files from one place to another. Each time the
    > file copies over it takes roughly 10 seconds per file (depending on how
    > large the file is).
    >
    > In the meantime, I need my JPanel label to update with the current number of
    > files copied over so far.
    >
    > I know from looking at the FAQs for this newsgroup that the GUI isn't
    > updating because it probably needs a new thread, but as a complete newbie to
    > threads, I'm wondering if I really need to learn about Threads to get my
    > relatively simple job done. My code simply runs in a for loop -
    >
    > int count=0;
    >
    > for (int i=0; i < 12; i++) {
    >
    > mycopyOverFileMethod();
    > count++;
    > label.setText("Files Copied:" + count);
    >
    > // Why is there no simple way in java just to put here something like :
    > // label.redraw();
    > // that avoids the need for threads??
    >
    > }
    >
    > Is there something simple I could do?
    >
    > TIA
    >
    >


    OK, brace yourself :)

    Yes, you will need threaded code to do this, but it should be reasonably
    simple. You will need a basic understanding of threading in Java but it
    is quite straightforward to do things like this.

    Repaint will not work because it will simply queue the component for
    repainting when the AWT thread (EDT) is available, and it wont be
    available until your method returns.

    Once you have gotten to grips with the basics of threading, create a
    Runnable that does the file copy, and in between each file copy, change
    your label text... however... there is something else you must understand...

    You should not do any manipulation of visual components on any thread
    but the AWT thread, visual components are not thread safe and may behave
    strangely if you do not follow this rule. Fortunately, there is a class
    called SwingUtilities that will allow you to pass tasks from your worker
    thread to the AWT thread. SwingUtilities.invokeLater(Runnable) will
    allow you to provide a task which will be run at some point (when AWT
    thread gets around to it) and SwingUtilities.invokeAndWait(Runnable)
    will pass the task on a block until it has been ran. You probably want
    the latter in this case.

    So, your code will look something similar to this...


    private final JLabel statusLabel;

    public void copyFiles()
    {
    Thread copyThread = new Thread(new Runnable()
    {
    public void run()
    {
    while(...)//there are more files to copy
    {
    //copy file
    SwingUtilities.invokeAndWait(new Runnable()
    {
    public void run()
    {
    //Increment label value
    }
    });
    }
    }
    }).start();
    }



    ....but clean it up a bit :)
     
    Wesley Hall, Dec 5, 2006
    #12
  13. Guest

    Daniel Dyer Guest

    On Tue, 05 Dec 2006 17:27:44 -0000, Colin Miller <> wrote:

    > Ok, how about this. Create a new class of type Runnable (You'll need
    > to read up a bit on threading on this, and it's good to know anyway).
    > Inside of that class is where you will do your file copying. Also in
    > that class, have a variable to store whatever class holds your JPanel.
    > When creating an instance of this new class, pass it a reference to
    > that class for callback.
    >
    > In your main class, or wherever you initiate the file copying, create
    > an instance of this new class and pass it "this" and set it to run. In
    > the class that does the file copying, after you finish copying a file,
    > you'll call a callback method to do the form update. Unfortunately, I'm
    > bad at explaining it.. I'll put some psudocode for you.
    >


    <Snipped code>

    The basic approach is sound, but you should not call any Swing methods
    (with the exception of some text component methods that are explicitly
    marked as thread-safe) from any thread other than the Event Dispatch
    Thread. So instead of directly calling setText on the label, you need to
    submit a Runnable to the Event Dispatch Thread via one of the methods in
    SwingUtilities (invokeLater or invokeAndWait). The run method for this
    Runnable will perform any necessary GUI updates.

    Dan.


    --
    Daniel Dyer
    http://www.uncommons.org
     
    Daniel Dyer, Dec 5, 2006
    #13
  14. Guest

    Daniel Dyer Guest

    On Tue, 05 Dec 2006 18:55:52 -0000, Wesley Hall <>
    wrote:

    > OK, brace yourself :)
    >
    > Yes, you will need threaded code to do this, but it should be reasonably
    > simple. You will need a basic understanding of threading in Java but it
    > is quite straightforward to do things like this.
    >
    > Repaint will not work because it will simply queue the component for
    > repainting when the AWT thread (EDT) is available, and it wont be
    > available until your method returns.
    >
    > Once you have gotten to grips with the basics of threading, create a
    > Runnable that does the file copy, and in between each file copy, change
    > your label text... however... there is something else you must
    > understand...
    >
    > You should not do any manipulation of visual components on any thread
    > but the AWT thread, visual components are not thread safe and may behave
    > strangely if you do not follow this rule. Fortunately, there is a class
    > called SwingUtilities that will allow you to pass tasks from your worker
    > thread to the AWT thread. SwingUtilities.invokeLater(Runnable) will
    > allow you to provide a task which will be run at some point (when AWT
    > thread gets around to it) and SwingUtilities.invokeAndWait(Runnable)
    > will pass the task on a block until it has been ran. You probably want
    > the latter in this case.


    The SwingWorker class provides a way of doing all this without having to
    care too much about the underlying threads, which might be easier for the
    OP if they are unfamiliar with threading.

    You just have to sub-class SwingWorker and implement a couple of methods.
    The base class deals with making sure they are invoked on the appropriate
    threads.

    SwingWorker has finally been added to the core API in Java 6
    (http://java.sun.com/javase/6/docs/api/javax/swing/SwingWorker.html).
    Unless you are on the bleeding edge, you're probably not using Java 6, but
    you can download a copy of SwingWorker to use with older runtimes. It's
    available from the SwingLabs project on java.net
    (https://swingworker.dev.java.net/).

    Dan.

    --
    Daniel Dyer
    http://www.uncommons.org
     
    Daniel Dyer, Dec 5, 2006
    #14
  15. Daniel Dyer wrote:
    > On Tue, 05 Dec 2006 17:27:44 -0000, Colin Miller <> wrote:
    >
    >> Ok, how about this. Create a new class of type Runnable (You'll need
    >> to read up a bit on threading on this, and it's good to know anyway).
    >> Inside of that class is where you will do your file copying. Also in
    >> that class, have a variable to store whatever class holds your JPanel.
    >> When creating an instance of this new class, pass it a reference to
    >> that class for callback.
    >>
    >> In your main class, or wherever you initiate the file copying, create
    >> an instance of this new class and pass it "this" and set it to run. In
    >> the class that does the file copying, after you finish copying a file,
    >> you'll call a callback method to do the form update. Unfortunately, I'm
    >> bad at explaining it.. I'll put some psudocode for you.
    >>

    >
    > <Snipped code>
    >
    > The basic approach is sound, but you should not call any Swing methods
    > (with the exception of some text component methods that are explicitly
    > marked as thread-safe) from any thread other than the Event Dispatch
    > Thread. So instead of directly calling setText on the label, you need
    > to submit a Runnable to the Event Dispatch Thread via one of the methods
    > in SwingUtilities (invokeLater or invokeAndWait). The run method for
    > this Runnable will perform any necessary GUI updates.
    >
    > Dan.
    >
    >
    > --Daniel Dyer
    > http://www.uncommons.org


    So this is how you do it in the simplest form. It looks really complex
    but in reality it is very simple. Look at the code pieces and look at
    the rules in comments.

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

    public class test {
    //
    // EventQueue.invokeLater(r) is used to run a Runnable piece of code on
    // the event dispatch thread or EDT.
    //
    // new Thread(r).start() is used to run a Runnable piece of code on
    a new
    // thread.
    //
    // The Swing GUI must be created on the EDT
    //
    // Code that takes a lot of time cannot be run on the EDT or the update
    // of the GUI will be prevented until it is done.
    //
    // All code that updates the GUI must be run on the EDT
    //
    public static void main(String[] args) {
    Runnable r = new Runnable() {
    public void run() {
    final JFrame f = new JFrame();
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    final JLabel l = new JLabel(" ");
    f.add(l,BorderLayout.NORTH);

    JButton b = new JButton("Copy");
    b.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent ae) {
    Runnable r = new Runnable() {
    public void run() {
    try {
    // the sleep is to simulate copying
    files
    for (int i=0; i<10; i++) {
    final int fn = i;
    Runnable r = new Runnable() {
    public void run() {
    l.setText("Copying File
    #" +
    Integer.toString(fn));
    }
    };
    EventQueue.invokeLater(r);
    // copy file here
    Thread.sleep(1000);
    }
    Runnable r = new Runnable() {
    public void run() {
    l.setText("All files copied");
    }
    };
    EventQueue.invokeLater(r);
    } catch (InterruptedException ie) {
    ie.printStackTrace();
    }
    }
    };
    new Thread(r).start();
    }
    });
    f.add(b,BorderLayout.SOUTH);

    f.pack();
    f.setVisible(true);
    }
    };
    EventQueue.invokeLater(r);
    }
    }

    --

    Knute Johnson
    email s/nospam/knute/
     
    Knute Johnson, Dec 5, 2006
    #15
  16. Guest

    Nigel Wade Guest

    Oliver Wong wrote:

    >
    > <> wrote in message
    > news:...
    >> lid wrote:
    >>> I've got a method that copies files from one place to another. Each time
    >>> the
    >>> file copies over it takes roughly 10 seconds per file (depending on how
    >>> large the file is).
    >>>
    >>> In the meantime, I need my JPanel label to update with the current number
    >>> of
    >>> files copied over so far.

    >>
    >> Yes, you need threads, but it's not that hard. You make a class that
    >> implements Runnable or extends Thread. Then you can do all ten files
    >> at once, if you choose to!

    >
    > It's not super hard, but it's not super easy either. This tutorial
    > should get you started:
    > http://java.sun.com/docs/books/tutorial/essential/concurrency/
    >
    > - Oliver


    I was going to recommend the tutorial on Swing, which used to include very good
    examples on how to perform tasks in threads, and how to use JProgressBar to
    monitor progress. But this has now been replaced by a pretty useless one which
    is completely dependent on Java 6 and the new SwingWorker. It seems that Sun no
    longer consider that there is any other way to use threads in Swing...

    If anyone knows where the old "Creating a GUI with JFC/Swing" can be found, I'd
    be grateful for a link, because I used that tutorial extensively.

    --
    Nigel Wade, System Administrator, Space Plasma Physics Group,
    University of Leicester, Leicester, LE1 7RH, UK
    E-mail :
    Phone : +44 (0)116 2523548, Fax : +44 (0)116 2523555
     
    Nigel Wade, Dec 6, 2006
    #16
  17. Guest

    Alex Hunsley Guest

    Nigel Wade wrote:
    > Oliver Wong wrote:
    >
    >> <> wrote in message
    >> news:...
    >>> lid wrote:
    >>>> I've got a method that copies files from one place to another. Each time
    >>>> the
    >>>> file copies over it takes roughly 10 seconds per file (depending on how
    >>>> large the file is).
    >>>>
    >>>> In the meantime, I need my JPanel label to update with the current number
    >>>> of
    >>>> files copied over so far.
    >>> Yes, you need threads, but it's not that hard. You make a class that
    >>> implements Runnable or extends Thread. Then you can do all ten files
    >>> at once, if you choose to!

    >> It's not super hard, but it's not super easy either. This tutorial
    >> should get you started:
    >> http://java.sun.com/docs/books/tutorial/essential/concurrency/
    >>
    >> - Oliver

    >
    > I was going to recommend the tutorial on Swing, which used to include very good
    > examples on how to perform tasks in threads, and how to use JProgressBar to
    > monitor progress. But this has now been replaced by a pretty useless one which
    > is completely dependent on Java 6 and the new SwingWorker. It seems that Sun no
    > longer consider that there is any other way to use threads in Swing...
    >
    > If anyone knows where the old "Creating a GUI with JFC/Swing" can be found, I'd
    > be grateful for a link, because I used that tutorial extensively.


    Hmmg, that's annoying! Could you find it on archive.org? (They cache
    bits of the internet at various points, see the "waybackmachine" thingy.)
    lex

    >
     
    Alex Hunsley, Dec 6, 2006
    #17
  18. Guest

    Alex Hunsley Guest

    lid wrote:
    >> Try calling label.repaint(); after you set the text. Or if you're using
    >> say a JFrame, try calling the JFrame's repaint(); method.
    >>
    >> It's possible that even though you updated the component, it was never
    >> painted to the screen.

    >
    > Thanks for the suggestions - I'd already tried that - it just doesn't update
    > until the for loop gets to the end then it updates the label and obviously
    > not as intended (ie only updates it with the finishing number rather than
    > updating it with the current number as it goes along)


    It looks like you're doing the processing in the event despatch thread.
    No GUI repainting can happen if you're hogging that thread. Let me
    guess, you handle some GUI event (e.g. a button was pressed) by
    launching into the given code, right? If so, that's your problem. You
    need to fork off a different thread that contains the above code (for
    copying each file and doing count++ etc. A call to repaint() may be
    needed, but possibly not.)
    lex


    >
    > : (
    >
    >
     
    Alex Hunsley, Dec 6, 2006
    #18
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    9
    Views:
    474
    Harish
    Jan 12, 2005
  2. yoda
    Replies:
    2
    Views:
    462
    =?utf-8?Q?Bj=C3=B6rn_Lindstr=C3=B6m?=
    Aug 1, 2005
  3. threads without threads

    , Aug 27, 2004, in forum: C Programming
    Replies:
    4
    Views:
    432
    William Ahern
    Aug 27, 2004
  4. Pedro Pinto

    Java Threads - Get running threads

    Pedro Pinto, Apr 8, 2008, in forum: Java
    Replies:
    2
    Views:
    1,483
    Arne Vajhøj
    Apr 9, 2008
  5. Une bévue
    Replies:
    0
    Views:
    176
    Une bévue
    Jun 14, 2006
Loading...

Share This Page