• Post Reply Bookmark Topic Watch Topic
  • New Topic

Different IllegalMonitorStateException question...

 
James Brooks
Gunslinger
Ranch Hand
Posts: 165
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ladies/gents,

Apparently threads aren't as simple as I thought. I'm getting an IllegalMonitorStateException upon calling i.notify() in my get() method, and I don't know why. The method is synchronized on i, and my thought was: If my main() method looks like this

, then thread1 would reduce inventory by one, and at the end when I release the lock, thread2 would take over when I call i.notify(). Apparently that's not the case, as I get the exception right there. What am I overlooking? This method is synchronized on i, so what is the problem? Thanks in advance!


myThread class:


item class:

 
Steve Luke
Bartender
Posts: 4181
22
IntelliJ IDE Java Python
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
When you call the methods thread1.get() and thread2.get() you are not calling those methods in different threads. You are executing them in the main thread, in sequence. You would need to move those calls into another thread (call them from a Thread's run() method for example) in order for them to be executed in parallel.

Also, I don't see anywhere were you are are synchronizing on i. Your method is declared as:
public synchronized void get(item i)
Which synchronizes on the instance of the myThread Object. Since you are using two different Objects that means your 'myThread' Objects would never synch with each other.

I don't see any additional
synchronized(i)
statements that would then synchronize on i.

I think you need to review the Threading tutorial: Found Here
Or get a good book on concurrency.

 
James Brooks
Gunslinger
Ranch Hand
Posts: 165
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Steve Luke wrote:When you call the methods thread1.get() and thread2.get() you are not calling those methods in different threads. You are executing them in the main thread, in sequence. You would need to move those calls into another thread (call them from a Thread's run() method for example) in order for them to be executed in parallel.



OK, makes sense. Thank you.


Also, I don't see anywhere were you are are synchronizing on i. Your method is declared as:
public synchronized void get(item i)
Which synchronizes on the instance of the myThread Object. Since you are using two different Objects that means your 'myThread' Objects would never synch with each other.

So, what, then, is the purpose of a method with the 'synchronized' keyword? I thought that that was what synchronized the object that was passed as a parameter. I guess not...


I don't see any additional
synchronized(i)
statements that would then synchronize on i.

What you have said so far makes sense. However, the Sun tutorial is, as usual, clear as mud to me. I thought that a 'lock' was a field that served as a 'busy status' check during access/update by another thread. The tutorial did NOT clear that up at all. I've scoured the web and haven't found a down-to-earth explanation, and my intro and DSA books have nothing on the subject. Maybe you could attempt to clear up the role of a lock inside the synchronized statement?

Thanks again!
 
Steve Luke
Bartender
Posts: 4181
22
IntelliJ IDE Java Python
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Patrick Brooks wrote:
So, what, then, is the purpose of a method with the 'synchronized' keyword? I thought that that was what synchronized the object that was passed as a parameter. I guess not...


That is incorrect. The synchronized method locks on the object. There are a couple of reasons to do it. For example, lets say you had an object called DataStore with a read and a write method:


Now, if we wanted to use DataStore in multiple threads we can get in trouble if one thread tries to read at the same time as another tries to write. In addition, if two threads tried to write at the same time bad things can happen. So we use the synchronized key word on the method, which means only one method with the synchronized key word can be executed on that object at a time:


If thread1 starts to write, then it gains the lock on the DataStore instance. When thread2 tries to read, or thread3 tries to write other data it tests DataStore's lock, finds that the lock is held by thread1, so they have to wait. Then when thread1 is done one of the other threads can get in to do their work. When the second thread is done the third can do its job. The result is that you are sure only one thread at a time can run the important methods (the ones that might break if run in parallel) at a time.


Maybe you could attempt to clear up the role of a lock inside the synchronized statement?


Think of the lock as a gate - When code gets into the the gate it automatically closes so only one thread can get into it at a time. There are a few ways the gate can open again:
1) The executing code leaves the block that is synchronized
2) The executing code calls wait() on the object synchronized to (which releases 'opens the gate' and makes the code stop executing until it is notified.

I wish I could go into more details, but I don't think I can do it justice. Try to go through the tutorials again. If your books don't cover it then get some that do. Forums just aren't the correct medium for this sort of thing.
 
James Brooks
Gunslinger
Ranch Hand
Posts: 165
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks for the tips so far. Well, I changed it around to have the two threads call get() on the item from within the run() method of the myThread class, but the threads are hogging (wait doesn't have any effect, the first thread continues until termination of the loop), and I'm not quite sure why. See below for my implementation. Does this maybe have to do with them being instantiated from the same class in which they are acting?

 
Steve Luke
Bartender
Posts: 4181
22
IntelliJ IDE Java Python
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You are still calling both get() methods from the same Thread, so only one will run at a time.

You need to have the get() method execute out of different threads. Here is an example (pardon the complexity I will try to explain):


Read the comments, I hope they explain a bit about what I did. I use a Runnable rather than subclassing Thread because it is more versatile and is better suited to doing tasks.

Note that I did not bother with any item.busy calls for inside Item. You don't need them. The synchronized(item) block does that, while the item.wait() and item.notify() allow you to switch between active threads. Also note that I use capital letters for the start of Class names and lower case letters for variable names. This is opposite of what you did, I think, but follows Sun's standards - something you should start to do.
 
James Brooks
Gunslinger
Ranch Hand
Posts: 165
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thank you for the example! It's much clearer now!
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!