Results 1 to 20 of 21
Thread: java.awt.Thread
- 07-26-2009, 10:51 AM #1
Senior Member
- Join Date
- Nov 2007
- Posts
- 160
- Rep Power
- 6
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:
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...Java Code:Thread myThread = new Thread(new Runnable() { @Override public void run() { // import songs etc } }); thread.start();
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...
- 07-26-2009, 04:56 PM #2
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?
- 07-26-2009, 08:54 PM #3
Senior Member
- Join Date
- Nov 2007
- Posts
- 160
- Rep Power
- 6
Here's how the main program was started:
a while loop where? The only code to do with this is an actionPerformed event that makes the Thread:Java Code:EventQueue.invokeLater(new Runnable() { public void run() { // initialise GUI etc } }
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?Java Code:Thread myThread = new Thread(new Runnable() { @Override public void run() { myMusicLibrary.addAFolderToMyMusicLibrary(theFolderISelected); } }); thread.start();
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.
- 07-27-2009, 01:27 AM #4
In your code you say:
Do you mean:Java Code:thread.start();
? Because that makes a differenceJava Code:myThread.start();
- 07-27-2009, 01:20 PM #5
Senior Member
- Join Date
- Nov 2007
- Posts
- 160
- Rep Power
- 6
Yes, sorry. I meant to say myThread.start()
- 07-27-2009, 02:09 PM #6
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()); } } } }
- 07-27-2009, 05:21 PM #7
Senior Member
- Join Date
- Nov 2007
- Posts
- 160
- Rep Power
- 6
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.
- 07-27-2009, 09:47 PM #8
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 } } }
- 07-27-2009, 10:50 PM #9
Senior Member
- Join Date
- Nov 2007
- Posts
- 160
- Rep Power
- 6
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?
- 07-27-2009, 11:07 PM #10
You need to use the synchronized key word. This creates a semaphore which prevents concurrent access. Here is an example:
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: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)); } } } }
More about synchronized:Java Code:Object lock = new Object(); synchronized(lock){ System.out.println("Hi!"); }
Synchronized Methods (The Java™ Tutorials > Essential Classes > Concurrency)
- 07-28-2009, 07:37 AM #11
Senior Member
- Join Date
- Nov 2007
- Posts
- 160
- Rep Power
- 6
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.
- 07-28-2009, 01:51 PM #12
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?
- 07-28-2009, 01:53 PM #13
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.
- 07-28-2009, 02:35 PM #14
Senior Member
- Join Date
- Nov 2007
- Posts
- 160
- Rep Power
- 6
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... ;-)
- 07-28-2009, 04:04 PM #15
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).
- 07-28-2009, 10:13 PM #16
Senior Member
- Join Date
- Nov 2007
- Posts
- 160
- Rep Power
- 6
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.
- 07-28-2009, 10:28 PM #17
The threads do not need to be synchronized, only the accessor methods. For example, this is bad:
This is good: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); } } }); }
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.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); } } }); }
- 07-29-2009, 06:47 AM #18
Senior Member
- Join Date
- Nov 2007
- Posts
- 160
- Rep Power
- 6
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?
- 07-29-2009, 03:50 PM #19
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.
- 07-29-2009, 04:54 PM #20
Senior Member
- Join Date
- Nov 2007
- Posts
- 160
- Rep Power
- 6
Similar Threads
-
Difference between Thread.yield() and Thread.sleep() methods
By Nageswara Rao Mothukuri in forum New To JavaReplies: 12Last Post: 07-30-2010, 05:37 PM -
Exception in thread "Thread-22" java.lang.NoClassDefFoundEthen screen just sits there
By bnh14 in forum Java AppletsReplies: 3Last Post: 11-06-2008, 04:24 PM -
data from the main/GUI thread to another runnin thread...
By cornercuttin in forum Threads and SynchronizationReplies: 2Last Post: 04-23-2008, 10:30 PM -
If JNI thread call the java object in another thread, it will crash.
By skaterxu in forum Advanced JavaReplies: 0Last Post: 01-28-2008, 07:02 AM


LinkBack URL
About LinkBacks
Reply With Quote

Bookmarks