Page 1 of 2 12 LastLast
Results 1 to 20 of 21

Thread: java.awt.Thread

  1. #1
    carderne is offline Senior Member
    Join Date
    Nov 2007
    Posts
    160
    Rep Power
    7

    Default java.awt.Thread

    In my music program, I have a method to import a folder full of music files. If this is a very big folder, it can obviously take quite a while to perform.

    The following is the code I used to do the importing in another thread:
    Java Code:
    Thread myThread = new Thread(new Runnable() {
        @Override
        public void run() {
            // import songs etc
        }
    });
    
    thread.start();
    And then I used thread.join() to wait for it to end to display a message or whatever. However, although this does import the songs, it still makes the rest of the program unusable...

    I've been testing it with my 40 or so GB music library and as soon I click to import, the rest of the program stops working until the import is complete.

    What have I done wrong? Why hasn't it been started in a new thread?

    The only problem I can think of is that this new thread still uses an object that the rest of the program uses, but nothing works during the import... Menu items don't open etc...

  2. #2
    quad64bit's Avatar
    quad64bit is offline Moderator
    Join Date
    Jul 2009
    Location
    VA
    Posts
    1,323
    Rep Power
    7

    Default

    Its hard to say from just what you provided. If the GUI itself is not in its own thread, it can lag like that. I would need to see more of your code in order to see whats going on. You're right in saying that putting a process in a sep. thread should prevent your gui from lagging, so the primary thread of the program must be waiting for the result of the action or something. Perhaps you have a while loop thats holding things up?

  3. #3
    carderne is offline Senior Member
    Join Date
    Nov 2007
    Posts
    160
    Rep Power
    7

    Default

    Here's how the main program was started:
    Java Code:
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            // initialise GUI etc
        }
    }
    a while loop where? The only code to do with this is an actionPerformed event that makes the Thread:

    Java Code:
    Thread myThread = new Thread(new Runnable() {
        @Override
        public void run() {
            myMusicLibrary.addAFolderToMyMusicLibrary(theFolderISelected);
        }
    });
    
    thread.start();
    That is pretty much all that happens there. I tested with other code in the run() method and whatever put there causes everything else to stop working... I mean the entire GUI won't respond at all to button clicks until the run() method has completed... Maybe how I created my main GUI doesn't allow other threads to run simultaneously?

    I know I've done a little multi-threaded something or other before but I can't remember what I did or how I did it...

    Thanks for your help.

  4. #4
    quad64bit's Avatar
    quad64bit is offline Moderator
    Join Date
    Jul 2009
    Location
    VA
    Posts
    1,323
    Rep Power
    7

    Default

    In your code you say:
    Java Code:
    thread.start();
    Do you mean:
    Java Code:
    myThread.start();
    ? Because that makes a difference

  5. #5
    carderne is offline Senior Member
    Join Date
    Nov 2007
    Posts
    160
    Rep Power
    7

    Default

    Yes, sorry. I meant to say myThread.start()

  6. #6
    quad64bit's Avatar
    quad64bit is offline Moderator
    Join Date
    Jul 2009
    Location
    VA
    Posts
    1,323
    Rep Power
    7

    Default

    I made some example code to simulate your situation, and it works fine. So I stand by my original statement in that your interface is waiting for something in your processing thread instead of simply periodically polling it for a result. Here is my example, try it out:
    Java Code:
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JTextField;
    
    /**
     * @author Steffen Gates
     */
    public class GUI {
    
        public static void main(String[] args) {
            new GUI();
        }
        JFrame window;      //The whole window
        JPanel panel;       //A place to put things in the window
        JTextField textIn;  //input
        JLabel label;       //output
        JLabel output;
        JButton button;     //simple button
    
        public GUI() {
            window = new JFrame();
            window.setSize(640, 150);
            window.setLocationRelativeTo(null);             //Center the window
            panel = new JPanel();
            textIn = new JTextField();
            textIn.setText("Type something here.");
            textIn.setColumns(50);                          //50 char's wide
            label = new JLabel("Threads are running");    //default output
            output = new JLabel("0");
            button = new JButton("Then Click Me!");
            button.addActionListener(new ButtonListener()); //make button do something
            panel.add(textIn);          //Add everything to the panel
            panel.add(label);
            panel.add(button);
            panel.add(output);
            window.add(panel);          //add panel to the window
            window.setVisible(true);    //make window visible
            Thread thread = new Thread(new Runnable() {
    
                public void run() {
                    for (int i = 0; i < 100; i++) {
                        try {
                            Thread.sleep(1000);
                            output.setText("" + i);
                        } catch (InterruptedException ex) {
                            Logger.getLogger(GUI.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    }
                }
            });
    
            thread.start();
    
        }
    
        //To make an action listener, just make a class that implements
        //ActionListener and has a method called actionPerformed()
        class ButtonListener implements ActionListener {
    
            public void actionPerformed(ActionEvent e) {
                if (e.getActionCommand().compareTo("Then Click Me!") == 0) {
                    label.setText(textIn.getText());
                }
            }
        }
    }

  7. #7
    carderne is offline Senior Member
    Join Date
    Nov 2007
    Posts
    160
    Rep Power
    7

    Default

    Got it! Thanks, you helped me to realise why it was hanging - quite obvious actually.

    I had this code running in a method that was called when something was clicked. So even though it started a new thread, the rest of the GUI was still waiting for this method to complete... So now I made the threading code higher up the hierarchy and now the whole method is called from the new thread.

    So yes, you were right. The original interface was waiting...

    By the way, do have any idea what would be the difference between simply calling the constructor from the main method (as you have done in your example) or using EventQueue.invokeLater as I have done? I just copied that from the code that Netbeans creates if I remember correctly.

    Thanks very much for your help.

  8. #8
    quad64bit's Avatar
    quad64bit is offline Moderator
    Join Date
    Jul 2009
    Location
    VA
    Posts
    1,323
    Rep Power
    7

    Default

    I prefer to do it my way most of the time because the main method is creating an instance of itself. However, according to proper GUI coding etiquette (from what I understand) when you are creating threads you should use EventQueue.invokeLater because it is thread safe. I guess a small percent of the time creating some threads directly causes dead-lock, though I am not sure I actually ever seen this happen. The last few years that I have been working with multi-threaded apps, I simply create the threads similar to the way we did here. Most often I do it this way, which has always worked for me:
    Java Code:
    /**
     * @author Steffen Gates
     */
    public class Example {
        public static void main(String[] args) {
            new Example();
        }
    
        public Example(){
            //Just make a thread that runs unitil its done
            new Thread(new WorkerThread()).start();
            //Or if I want to monitor it
            Thread someThread = new Thread(new WorkerThread());
            someThread.start();
        }
        
        class WorkerThread implements Runnable{
            public void run() {
                //Do something for a while then terminate
            }
        }
    }

  9. #9
    carderne is offline Senior Member
    Join Date
    Nov 2007
    Posts
    160
    Rep Power
    7

    Default

    Thanks for the info. I've just thought of a problem possibly introduced by my threading - what if the new thread is running and then I do something else and both threads try to modify/access an object or something at the same time?

  10. #10
    quad64bit's Avatar
    quad64bit is offline Moderator
    Join Date
    Jul 2009
    Location
    VA
    Posts
    1,323
    Rep Power
    7

    Default

    You need to use the synchronized key word. This creates a semaphore which prevents concurrent access. Here is an example:
    Java Code:
    import java.util.Random;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    
    /**
     * @author Steffen Gates
     */
    public class Example {
        public static void main(String[] args) {
            new Example();
        }
    
        private int[] numbers;
    
        public Example(){
            numbers = new int[10];
            for(int i=0; i<10; i++){
                numbers[i] = i;
            }
    
            System.out.println("Initial:\n\r");
            printData();
    
            new Thread(new WorkerThread()).start();
            new Thread(new WorkerThread()).start();
            new Thread(new WorkerThread()).start();
            new Thread(new WorkerThread()).start();
            while(true){
                printData();
            }
        }
    
        public synchronized void setData(int index, int data){
            numbers[index] = data;
        }
    
        public synchronized void printData(){
            for(int i=0; i<numbers.length; i++){
                System.out.print(numbers[i]+",");
            }
            System.out.println("");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ex) {
                Logger.getLogger(Example.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    
        class WorkerThread implements Runnable{
            Random ran;
            public WorkerThread(){
                ran = new Random();
            }
            public void run() {
                while(true){
                    setData(ran.nextInt(10), ran.nextInt(10));
                }
            }
        }
    }
    The synchronized key word keeps multiple threads from using methods at the same time. You can also insert a synchronized block of code inside a method like this:
    Java Code:
    Object lock = new Object();
    synchronized(lock){
         System.out.println("Hi!");
    }
    More about synchronized:
    Synchronized Methods (The Java™ Tutorials > Essential Classes > Concurrency)

  11. #11
    carderne is offline Senior Member
    Join Date
    Nov 2007
    Posts
    160
    Rep Power
    7

    Default

    Thanks very much.

    Let me quickly explain my program. I have the the main GUI, which creates an object of the Library class, which creates an ArrayList of Playlist objects, each of which creates an ArrayList of Song objects.

    What my new thread will be doing is accessing a method in the Library object, which will call a method from one of the Playlist objects, which will create new Song objects. But there are lots of other methods - for playing songs, exporting playlists etc - that could try to access many of these objects too...

    I'm sorry I can't explain it very well. Say I had one song imported into my program. Then I import another 8000 songs and while that is happening I play my original song. Both threads could now try to access the same Playlist object... Is that not a problem?

    I'll read what you've linked though. That should help my understanding of it all.

  12. #12
    quad64bit's Avatar
    quad64bit is offline Moderator
    Join Date
    Jul 2009
    Location
    VA
    Posts
    1,323
    Rep Power
    7

    Default

    Its is not a problem as long as you use synchronized methods. In theory, as long as one thread is using a method that is modifying the array, another thread that has been asked to play a song from that array by a synchronized method will be forced to wait for the first method to finish. Even itunes behaves this way -- when a large import is happening, the user is forced to wait until completion before any new browsing or playback is allowed.

    If your threads are running in the background, this may give the appearance of the application becoming unresponsive. To avoid this, you could make a progress bar window that pops to the front, which is called by a method in the GUI class. If you code it like you were having trouble originally, it makes the GUI unresponsive to the user (a good thing while importing) and could simply update a progress bar.

    Or you could do like iTunes and only do what I said while new songs are being parsed, and once the list is complete and you are only waiting for songs to physically copy to a new location you could return control to the user.

    May I ask -- what will you use for playback? The Java Media Framework?

  13. #13
    quad64bit's Avatar
    quad64bit is offline Moderator
    Join Date
    Jul 2009
    Location
    VA
    Posts
    1,323
    Rep Power
    7

    Default

    One more thing -- I suggest you do parsing and file copy in two separate steps. To parse a huge folder of music, even 100,000 songs might only take a few seconds or a minute, however doing something with those files (i.e. moving them to a new location) could take hours. Parse first, process/move later.

  14. #14
    carderne is offline Senior Member
    Join Date
    Nov 2007
    Posts
    160
    Rep Power
    7

    Default

    It's quite a basic player - when I see import, I mean import the metadata. I'm not doing anything with the original files. So it's only actually parsing.

    I found an open source MP3 (and ogg and wav I think) playing library on javazoom.net. It's not perfect but it works well enough for my purposes. Also found another library to read in song metadata.

    So what you're saying is that I don't need to make all the methods synchronised, just the ones that will be called from the new thread. i.e. So long as at least one of the threads trying to access a resource is synchronised, all is well.

    What I have at the moment is that the player's progress bar (track progress) becomes indeterminate during an import to show that something is happening and then goes back to showing the song's progress - if any is playing.

    I'm going to test around and see if I get any conflict and if there is anything that will cause considerable unresponsiveness, I'll make the progress thing in a modal JDialog. Of course then my threading won't be needed... ;-)

  15. #15
    quad64bit's Avatar
    quad64bit is offline Moderator
    Join Date
    Jul 2009
    Location
    VA
    Posts
    1,323
    Rep Power
    7

    Default

    Yes -- you only need to synchronize when working with shared data. So, any methods that either add to or read from an array should be synchronized if its possible that more than one thread could access/change them simultaneously (that includes the gui thread/main program thread and any others (i.e. your parse/addition to database thread).

  16. #16
    carderne is offline Senior Member
    Join Date
    Nov 2007
    Posts
    160
    Rep Power
    7

    Default

    But if two methods are trying to access a resource, is it fine if only one is synchronised, or do they both have to be synchronised?

    Sorry if I'm asking difficult questions but thanks for your patience.

  17. #17
    quad64bit's Avatar
    quad64bit is offline Moderator
    Join Date
    Jul 2009
    Location
    VA
    Posts
    1,323
    Rep Power
    7

    Default

    The threads do not need to be synchronized, only the accessor methods. For example, this is bad:
    Java Code:
        public int getValue(int index) {
            return array[index];
        }
    
        public void setValue(int index, int value) {
            array[index] = value;
        }
    
        public void go() {
            new Thread(new Runnable() {
    
                public void run() {
                    while (true) {
                        getValue(randomIndex);
                    }
                }
            });
            new Thread(new Runnable() {
    
                public void run() {
                    while (true) {
                        setValue(randomIndex, randomValue);
                    }
                }
            });
        }
    This is good:

    Java Code:
        public synchronized int getValue(int index) {
            return array[index];
        }
    
        public synchronized void setValue(int index, int value) {
            array[index] = value;
        }
    
        public void go() {
            new Thread(new Runnable() {
    
                public void run() {
                    while (true) {
                        getValue(randomIndex);
                    }
                }
            });
            new Thread(new Runnable() {
    
                public void run() {
                    while (true) {
                        setValue(randomIndex, randomValue);
                    }
                }
            });
        }
    Only the methods where assignment or viewing will occur need to be synchronized. That way when thread1 uses class A's set method, it can be safe in knowing that thread2 is not also using A's set (or get) methods because all the get/set methods in A are synchronized.

  18. #18
    carderne is offline Senior Member
    Join Date
    Nov 2007
    Posts
    160
    Rep Power
    7

    Default

    Ok I understand. What I was hoping was that, using your example above, only setValue() would have to be synchronised - and not getValue() - and that because one was synchronised, it would wait or make make other methods wait to access resources...

    If I do find conflicts from importing, I'll probably have to synchronise nearly every method... Is that fine?

  19. #19
    quad64bit's Avatar
    quad64bit is offline Moderator
    Join Date
    Jul 2009
    Location
    VA
    Posts
    1,323
    Rep Power
    7

    Default

    It is ok if every method is synchronized, you shouldn't notice a different as a user. You can also probably get away with not synchronizing the read() methods -- I'm honestly not sure what the policy on that its.

    My only thought is what happens when a thread is modifying an entry in an array list at the same time as another is reading that entry? Either a concurrent access exception will be thrown, or the old info will be read just before the new data is written, or it will work just fine. With a lock, the outcome is predictable.

  20. #20
    carderne is offline Senior Member
    Join Date
    Nov 2007
    Posts
    160
    Rep Power
    7

    Default

    Okay well I'll have a fiddle with everything that I've learnt and see how I do.

    Thanks again for your help.
    Last edited by carderne; 07-29-2009 at 07:40 PM.

Page 1 of 2 12 LastLast

Similar Threads

  1. Difference between Thread.yield() and Thread.sleep() methods
    By Nageswara Rao Mothukuri in forum New To Java
    Replies: 12
    Last Post: 07-30-2010, 06:37 PM
  2. Replies: 3
    Last Post: 11-06-2008, 05:24 PM
  3. data from the main/GUI thread to another runnin thread...
    By cornercuttin in forum Threads and Synchronization
    Replies: 2
    Last Post: 04-23-2008, 11:30 PM
  4. Replies: 0
    Last Post: 01-28-2008, 08:02 AM

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •