• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Tim Cooke
  • paul wheaton
  • Paul Clapham
  • Ron McLeod
Sheriffs:
  • Jeanne Boyarsky
  • Liutauras Vilda
Saloon Keepers:
  • Tim Holloway
  • Carey Brown
  • Roland Mueller
  • Piet Souris
Bartenders:

Wait() and Notify() failed

 
Ranch Hand
Posts: 75
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Everyone,

I have added a wait() method that cause my program keep waiting even with the Notify().

my goal
The "serial.write(ByteElement.toByteArray());" contain iteration list data, but i need to send it one by one, which means i need to send each data only after i receive corresponding response from "SerialDataListener" (it is a slow response).

What is the correct way of implementing wait(), notify() in this program? please help thanks in advanced.

 
Bartender
Posts: 4568
9
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I haven't thought through the whole thing, so I can't guarantee there's nothing else wrong. But the tricky part is this: you aren't calling wait() and notify() on the same objects. Can you see why?
 
Jeansonne Pierre
Ranch Hand
Posts: 75
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Matthew Brown,

Actually i still don't see it. I'm not too familiar with the usage of notify(), wait().
Seriously, i have no idea what objects they are calling now.
all the while I thought that as long as the notify() & wait() are in the same class, then they are calling/sharing the same object (Worker).
Mind to teach me or share with me your thought?

thanks
 
Jeansonne Pierre
Ranch Hand
Posts: 75
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I have tried my best to solve this, but still failed.
I'm wondering, is it a good idea if i add a new class (something like this), then i call this class from the previous code. please suggest.
If not, what modification should i do to the previous code. thanks. please help




 
Ranch Hand
Posts: 443
3
Eclipse IDE C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

I thought that as long as the notify() & wait() are in the same class



It's actually they should be on the same instance of the class, however in your case your not using the same class the wait is on an anonymous inner class of Worker which is not the same thing as Worker.

Try this ...



PS .

Waits should always be in loops ....

As described here ... object wait documentation

interrupts and spurious wakeups are possible, and this method should always be used in a loop:

synchronized (obj) {
while (<condition does not hold>)
obj.wait(timeout, nanos);
... // Perform action appropriate to condition
}

 
Jeansonne Pierre
Ranch Hand
Posts: 75
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Matthew Brown & Chris Hurst,

i saw it now, basically I'm not calling wait() and notify() on the same objects.
wait() is in Worker object
notify() is in the SwingWorker object (anonymous object)

So I've change it to

Worker.this.notify();

but still failed.
with the

Exception in thread "Thread-0" java.lang.IllegalMonitorStateException



I have tried to print out both object's identify to validate whether they are monitoring the same object, in fact, yes. Same object
but why still failed? please help :'(

 
Chris Hurst
Ranch Hand
Posts: 443
3
Eclipse IDE C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Jeansonne Pierre wrote:Hi Matthew Brown & Chris Hurst,

i saw it now, basically I'm not calling wait() and notify() on the same objects.
wait() is in Worker object
notify() is in the SwingWorker object (anonymous object)

So I've change it to

Worker.this.notify();

but still failed.
with the

Exception in thread "Thread-0" java.lang.IllegalMonitorStateException



I have tried to print out both object's identify to validate whether they are monitoring the same object, in fact, yes. Same object
but why still failed? please help :'(



Hi,

You are now notifying with the correct object but you will now be synchronized on the wrong one (that's what the exception means) i.e. the synchronized on the method process works on the this of the inner class, you need to sync on the this of the outer class to call notify and not get the exception you are seeing ...






You could simplify the code some what by writing a synchronized method in worker which does the notify as that would be synchronized on the correct this and you could call that from your inner class.

 
Jeansonne Pierre
Ranch Hand
Posts: 75
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Guys,

I have change the code to as below, no more exception, but the program still keep waiting at wait() point.




after that, i change to another version (without SwingWorker), and it works, but this still doesn't meet my goal. because i still need the SwingWorker. Please advice




 
Chris Hurst
Ranch Hand
Posts: 443
3
Eclipse IDE C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi,

Looking at what your actually doing ...

I do much java GUI work at the moment but it doesn't look like your using SwingWorker correctly, it might be easier if you give us the output your seeing.

doInBackground is meant to do a long running task it actually just adds a listener and returns immediately, which would call done immediately, I would have thought ?
Presumably the listener will call you back but that presumably is on a different thread not the worker as such. I don't think you do want a SwingWorker for this ?
 
Jeansonne Pierre
Ranch Hand
Posts: 75
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi guys, I'm so sorry, it's confusing that i make the discussion with so many version, so lets make this version as template.



Hi Chris Hurst,

FYI, each byteElement holding 5 objects/command
now i comes to the point that,
1st time when i click send "Button" with the output as below

Waiting || com.controller.Worker@fe5c8e
Notify || com.controller.Worker@fe5c8e
Device A-1
Waiting || com.controller.Worker@fe5c8e
Notify || com.controller.Worker@fe5c8e
Device B-2
Waiting || com.controller.Worker@fe5c8e
Notify || com.controller.Worker@fe5c8e
Device C-3
Waiting || com.controller.Worker@fe5c8e
Notify || com.controller.Worker@fe5c8e
Device D-4
Waiting || com.controller.Worker@fe5c8e
Notify || com.controller.Worker@fe5c8e
Device E-5




2nd time when i click send "Button"

Waiting || com.controller.Worker@1181a0d
Notify || com.controller.Worker@fe5c8e
Device A-1


the program keep waiting

it seems like the objects(fe5c8e VS 1181a0d) that being monitored is different for the second time i pressed send button.
But i have no idea how to make the program calling the same objects and i have no idea why it happen only at second time i pressing the button. it happened and keep waiting only at second time of button pressed!

please help :'(

Continue
https://coderanch.com/t/645981/threads/java/Wait-Notify-failed-Continue#2973637
 
Marshal
Posts: 28425
102
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You don't know what part of your code is creating new Worker objects? Neither do I; none of the code you posted creates any new Workers as far as I can see. So you're going to have to look elsewhere. There must be more code somewhere which creates a new Worker and calls its methods, so look for that. Then you'll have to decide what to do instead, if that isn't working.

However if it were me I would have written some simpler code to use that serial port stuff. Trying to start out by embedding it in a Swing application is too complicated. Try to write a class which controls the serial port by itself, in fact a class which encapsulates all of the processing of the serial port including opening it, reading and writing, and closing it. Then use an instance of that class in your Swing application once you get that working.
 
Jeansonne Pierre
Ranch Hand
Posts: 75
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Paul Clapham,

Opps, sorry, Basically the code which creating Worker object and calling sendCommand() is


I'm trying my best to fix this, to make it as simpler as possible, and etc. I'm still in learning curve, i need your help to point me something. as i'm stuck on this for few days :'( thanks.
 
Paul Clapham
Marshal
Posts: 28425
102
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You seem to be in the trap of writing code and messing about with it, and now your code is out of control. I suggest (again) that you stop digging yourself deeper into that hole and start again. I'm going to repeat my suggestion which I just made a little while ago:

Try to write a class which controls the serial port by itself, in fact a class which encapsulates all of the processing of the serial port including opening it, reading and writing, and closing it.



Right now you have a class called Worker (the name already suggests that your description of what a Worker is for is going to be too unfocused). That class seems to be tangled up with all kinds of other things from your application -- it knows about Passenger objects, and it's an inner class of something else which means it's tangled up with that as well. I suggest you need a class which doesn't know about any of those things at all. It should only know about the serial port. It should be able to open the port, send an array of bytes to the port, and return an array of bytes which is the response to the last command you sent.

Yes, that last part is the hard part. But you aren't helping yourself by entangling that logic with everything else in your application.
 
Paul Clapham
Marshal
Posts: 28425
102
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
And here's another suggestion: Don't try to use wait() and notify() to manage the threads necessary to deal with your serial port. Those methods are too hard for ordinary people like you and me to use -- as you are finding. It's far too easy to make a mess with them. Use something out of the java.util.concurrent package, those things were put there to encapsulate the horrible raw threading primitives (wait and notify) into objects which deal with all the threading crap and are easy to use. An ArrayBlockingQueue might be suitable; the listener which waits for data from the serial port should package up that data and put it on the queue, and whatever needs that data in your application should get it from the queue.
 
Chris Hurst
Ranch Hand
Posts: 443
3
Eclipse IDE C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I agree with Paul it's very confusing.

Looking at what you have shown us do you have something that unregisters the listener i.e. what stops the first worker being a listener for any subsequent send on a new worker which you seem to make . Should the add listener bit being in more of an init type method i.e. it looks like everytime you send you add a new listener.

I suspect you shouldn't have a SwingWorker at all, you would just register a listener (only one) at program startup ? send messages from the GUI (EDT) thread on button clicks (just call send no wait) and in the listener method (SerialDataListener callback) do a SwingUtilies.invokeLater to update your GUI on the EDT (GUI thread) eg change some text to say this was the reply I got or whatever.
 
Jeansonne Pierre
Ranch Hand
Posts: 75
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Guys,

First of all, thanks for all the response/suggestion/help/advise. Sincerely appreciate it. Because i really need your help for now.

1. You all are right, i shouldn't use SwingWorker at all. that's why for the latest code(Version 1.0), i have removed it. just that the class name remain Worker(but doesn't has any SwingWorker at all)

Version 1.0 code as below



2. Sorry, maybe I still don't understand. from what i see here, the code is already encapsulate only serial port controlling functionality. which part i can simplify more or break it to another class? please suggest.

Try to write a class which controls the serial port by itself, in fact a class which encapsulates all of the processing of the serial port including opening it, reading and writing, and closing it.



3. oh guys, i never know i can use ArrayBlockingQueue for this case, and i never use this either. Thanks. i will try it out today and reply to here as soon as possible.

4. FYI, the Serial class that i'm using is from http://pi4j.com/apidocs/index.html?com/pi4j/io/serial/Serial.html

5. I will try out the ArrayBlockingQueue class as suggested by today, it should be a better appproach. but no matter how, i'm still wondering & curious that why my code (Version 1.0) above got me the correct response for the first sendCommand(), and causing problem only at second time of sendCommand(). It seems like it pretty close to my goal. i still feel like wanna get it done before continue to the ArrayBlockingQueue class.

As you can see, the output

1st command

Waiting || com.controller.Worker@fe5c8e
Notify || com.controller.Worker@fe5c8e
Device A-1
Waiting || com.controller.Worker@fe5c8e
Notify || com.controller.Worker@fe5c8e
Device B-2
Waiting || com.controller.Worker@fe5c8e
Notify || com.controller.Worker@fe5c8e
Device C-3
Waiting || com.controller.Worker@fe5c8e
Notify || com.controller.Worker@fe5c8e
Device D-4
Waiting || com.controller.Worker@fe5c8e
Notify || com.controller.Worker@fe5c8e
Device E-5



2nd command

Waiting || com.controller.Worker@1181a0d
Notify || com.controller.Worker@fe5c8e
Device A-1



It seems like the Notify object still remain on the same old object (fe5c8e) on the second command. Why it still remain on the same old object? The second sendCommand should have new Object which is (1181a0d) . Please help
 
Jeansonne Pierre
Ranch Hand
Posts: 75
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Guys,

We manage to get it finally and it works successfully, thank you guys. As you guy suggested, break it into two classes.
FYI: the key is the "static" keyword on the reference variable Synchronizer.

But guys, I'm still a bit doubt on my code. i feel something wrong there and i got a strong feeling that the usage of Thread notify(),wait() in my code is totally wrong. (not optimized, bad coding style, something hard coded, wrong usage of Thread, bad design) i'm not so sure, please advise.
And in this case, should I use ArrayBlockingQueue or Wait()Notify() ? Please advise.
Is that okay i'm using "static" reference variable over here?
because i get this by just lucky, try and error and suddenly i get it. if you ask me why previous code doesn't work? i cannot answer, because i don't know, still in a blurr mode. Please help.

Class Listener.java


Class Synchronizer.java


Output

Button Clicked
Waiting || com.controller.Synchronizer@1dca662
Notifying || com.controller.Synchronizer@1dca662
Device A-1
Waiting || com.controller.Synchronizer@1dca662
Notifying || com.controller.Synchronizer@1dca662
Device B-2
Waiting || com.controller.Synchronizer@1dca662
Notifying || com.controller.Synchronizer@1dca662
Device C-3
Waiting || com.controller.Synchronizer@1dca662
Notifying || com.controller.Synchronizer@1dca662
Device D-4
Waiting || com.controller.Synchronizer@1dca662
Notifying || com.controller.Synchronizer@1dca662
Device E-5

Button Clicked
Waiting || com.controller.Synchronizer@c1cf45
Notifying || com.controller.Synchronizer@c1cf45
Device A-1
Waiting || com.controller.Synchronizer@c1cf45
Notifying || com.controller.Synchronizer@c1cf45
Device B-2
Waiting || com.controller.Synchronizer@c1cf45
Notifying || com.controller.Synchronizer@c1cf45
Device C-3
Waiting || com.controller.Synchronizer@c1cf45
Notifying || com.controller.Synchronizer@c1cf45
Device D-4
Waiting || com.controller.Synchronizer@c1cf45
Notifying || com.controller.Synchronizer@c1cf45
Device E-5

 
Jeansonne Pierre
Ranch Hand
Posts: 75
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Guys,

I have try out the version using ArrayBlockingQueue. But it seems like the output not in a correct sequence. I need the output in one by one, "serial.write()" only whenever there is any response.
From the output: It put two times then only consume, why? i need in the sequence put -> consume ->put -> consume ....
does this mean that i should use wait() notify() instead of ArrayBlockingQueue?? Please advise.

Put || com.controller.Synchronizer@6c8187
Put || com.controller.Synchronizer@6c8187
Consume || com.controller.Synchronizer@6c8187
Device A-1 Device B-2



class Synchronizer.java


Complete output as below

Button Clicked
Put || com.controller.Synchronizer@6c8187
Put || com.controller.Synchronizer@6c8187
Consume || com.controller.Synchronizer@6c8187
Device A-1 Device B-2
Put || com.controller.Synchronizer@6c8187
Consume || com.controller.Synchronizer@6c8187
Device C-3
Put || com.controller.Synchronizer@6c8187
Consume || com.controller.Synchronizer@6c8187
Device D-4
Put || com.controller.Synchronizer@6c8187
Consume || com.controller.Synchronizer@6c8187
Device E-5

Button Clicked
Put || com.controller.Synchronizer@7db59f
Put || com.controller.Synchronizer@7db59f
Consume || com.controller.Synchronizer@7db59f
Device A-1 Device B-2
Put || com.controller.Synchronizer@7db59f
Consume || com.controller.Synchronizer@7db59f
Device C-3
Put || com.controller.Synchronizer@7db59f
Consume || com.controller.Synchronizer@7db59f
Device D-4
Put || com.controller.Synchronizer@7db59f
Consume || com.controller.Synchronizer@7db59f
Device E-5

 
reply
    Bookmark Topic Watch Topic
  • New Topic