• Post Reply Bookmark Topic Watch Topic
  • New Topic

Sometimes my program workes, sometimes it does not, strange,why?

 
Forman Smith
Greenhorn
Posts: 14
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
This is a small task to simulate a ball falling and upspring。
Sometimes, when i click the button, it works well, the ball fall down and unspring , over and over.
But sometimes, after i cilck the button, the red just stay there, no movement.
What cause this? how to resolve this?
here is the code:

 
Forman Smith
Greenhorn
Posts: 14
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
If i change the line 64 from



to

it will work.
what is the difference?
 
Piet Souris
Rancher
Posts: 1631
36
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
hi Forman,

what happens is is that you start your thread, by constructing
your RoundPanel. At the time the Runnable is started, it might
very well be that the construction of your frame is not yet finished,
and in that case 'frame.getHeight()' will return 0.

Therefore, m is never smaller than tht height - 100 - 10, and so
the runnable never starts doing what you were hoping it would
do,

Your suggestion of replacing that statement with 'while (true)'
works because now you do not make that comparison anymore.

If you want to get it to work like you had in mind, look at the changes
I made. Only a few changes, but they will be clear.

Although it made no difference in all the runs that I made, I added
'volatile' to 'int flag'. That is because variable 'flag' in your thread
might be another flag than the flag in your main program.

There are more remakrs to be made though, like running from the
EDT, using synchronised, Swing Timers, and the lot.
If you are interested, let us know.

Greetz,
Piet

In this code, I start the thread after I knw for sure that my frame
is constructed and its height is known.

 
Forman Smith
Greenhorn
Posts: 14
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thank you so much, Piet Souris , you help me to know the reason and tell me how to modify it, thank you for your kindndss .
I find that you helped on changing these :
1、change the "int flag" to "volatile int flag"; to make sure the flag value is what i want , but not the value that may be changed by something else.
2、add "panel.start();" to make sure the panel start after the construction of frame is finished. Is my understand right?
3、put"Thread thread;" in front, i don't know the reason of this change-_-!!would you please tell me more?
 
Piet Souris
Rancher
Posts: 1631
36
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
hi Forman,

your remarks are mostly correct, but I will go through them to get it 100% correct.

1) Not exactly. A variable that is shared between two or more threads faces the following risks:

a) memory inconsistency. Your processor has, in all likelyhood, more than one core. Every
core has its own piece of memory on-board, and Threads are allowed to store variables
in the memory that belongs to the core that the Thread is running on.
So, you might change a variable, but chances are that this change is not seen by a thread
that has its own copy of that variable. Using 'volatile' ensures that your whole program only
has one place where that variable is stored.

b) thread interference. That is something that has to do with two threads writing at the same
time to the same shared variable, therefore one of the threads results might get lost. The way
to prevent that from happening is to use synchonization in some form.
You change 'flag' in a couple of places: in your main program when the button is clicked,
and in yout thread, where you alternate between flag = 1 and flag = 2.
Usually that will work, but there are no guarantees.

Anyway, this is quite complicated stuff. If you do want to work with threads, and who doesn't,
then a thorough read of the Oracle tutorial about Swing concurrency is essential.

2) yes

3) well, this wasn't actually necessary, I admit. In the constructor of 'RoundPanel' I said
'thread = new Thread(this)'.

and in the 'start' method I needed a reference to this thread. If I had used, in the constructor,
'Thread thread = new Thread(this)', then thread would be a local variable that would not
be available in the 'start' method. That's why I made 'thread' a member variable.

But of course I could have put 'Thread thread = new Thread(this)' into the start method,
and then I would not need 'thread' to be a member variable.
But I like a thread to have a name, so that I can always issue something like 'thread.interrupt()',
in an attempt to finish a thread. But that is not relevant here.

Greetz,
Piet
 
Forman Smith
Greenhorn
Posts: 14
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Piet Souris wrote:hi Forman,

your remarks are mostly correct, but I will go through them to get it 100% correct.

1) Not exactly. A variable that is shared between two or more threads faces the following risks:

a) memory inconsistency. Your processor has, in all likelyhood, more than one core. Every
core has its own piece of memory on-board, and Threads are allowed to store variables
in the memory that belongs to the core that the Thread is running on.
So, you might change a variable, but chances are that this change is not seen by a thread
that has its own copy of that variable. Using 'volatile' ensures that your whole program only
has one place where that variable is stored.

b) thread interference. That is something that has to do with two threads writing at the same
time to the same shared variable, therefore one of the threads results might get lost. The way
to prevent that from happening is to use synchonization in some form.
You change 'flag' in a couple of places: in your main program when the button is clicked,
and in yout thread, where you alternate between flag = 1 and flag = 2.
Usually that will work, but there are no guarantees.

Anyway, this is quite complicated stuff. If you do want to work with threads, and who doesn't,
then a thorough read of the Oracle tutorial about Swing concurrency is essential.

2) yes

3) well, this wasn't actually necessary, I admit. In the constructor of 'RoundPanel' I said
'thread = new Thread(this)'.

and in the 'start' method I needed a reference to this thread. If I had used, in the constructor,
'Thread thread = new Thread(this)', then thread would be a local variable that would not
be available in the 'start' method. That's why I made 'thread' a member variable.

But of course I could have put 'Thread thread = new Thread(this)' into the start method,
and then I would not need 'thread' to be a member variable.
But I like a thread to have a name, so that I can always issue something like 'thread.interrupt()',
in an attempt to finish a thread. But that is not relevant here.

Greetz,
Piet



Thanks a lot ,I understand most of it. You are really great.
 
Piet Souris
Rancher
Posts: 1631
36
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You're welcome!

Greetz,
Piet
 
Campbell Ritchie
Marshal
Posts: 52549
119
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
What does flag=1 mean?

It sounds as though you are trying to use numbers as booleans. Don't use numbers as booleans, since Java® supports the boolean type directly. You should be able to write flag = true; or similar.
 
Rob Spoor
Sheriff
Posts: 20819
68
Chrome Eclipse IDE Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Piet Souris wrote:Anyway, this is quite complicated stuff. If you do want to work with threads, and who doesn't,
then a thorough read of the Oracle tutorial about Swing concurrency is essential.

You know of the Oracle tutorial (Concurrency in Swing), yet your example code performs Swing actions (repainting) in a thread that is not the Event Dispatcher Thread. I'm sure you know that in this case, a javax.swing.Timer or a SwingWorker is a much better solution.
 
Piet Souris
Rancher
Posts: 1631
36
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Yes, I do know, I have had some discussions the other days about EDTs and the lot.
I'm sure you are aware of that.

And indeed, there are many things in the code to be commented on. You mention
the EDT and Swing timers, you could have mentioned quite some other things, especially
the use of 'frame.revalidate()'.

If you have given OP's opening post a thorough read, then you see that I only changed
that bit needed to make the code working. And I invited OP to ask for more information
if he wanted to. But for me, given OP's experience (as I estimate), I was satisfied
with the results.

If you think otherwise, then feel free to send in your replies, in which you show
and explain everything that OP should know.

Greetz,
Piet
 
Campbell Ritchie
Marshal
Posts: 52549
119
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Yes, we agreed last week that a Timer was the right way to handle animation. We know, as Rob has said, that Swing is generally not‑thread‑safe. I know there are a few supposedly thread‑safe methods, as you told us last week (though the API documentation for the method you mentioned did not say it was thread‑safe). We know that in this particular situation the threaded code will work 99% of the time. But 99% of the time is not good enough. You are not in a benign world, but a hostile world, where people are trying to steal your credit card number, etc. You want to teach code which works 100% of the time, as far as possible.
Teaching people to use multiple threads in a non‑thread‑safe framework is not at all helpful.
 
Consider Paul's rocket mass heater.
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!