1

I am an analog guy learning how to code on android so please bear with me if this question sounds stupid.

I understand the gist of synchronization. If i have data that two threads can access and modify it could lead to inconsistent values in the data variable in both threads.

It makes sense to make methods synchronized and lock them till one thread is done executing it (performing any conditional checks) but why would it matter with single statements? It would matter with multiple statements as theres a chance of thread one going out of runnable state in between 2 or more statements but i dont understand what the point is for a single statement.

Here is an example

if i have a listener that can be called from lets say a game thread and it modifies a data variable why would i do it this way...

    public void onCompletionListener(MediaPlayer player){
    synchronized (this){
        isPrepared = false;
       }
    }

i also have another method in my Music class called stop

   public void stop(){
   mediaPlayer.stop()
    synchronized(this){
    isPrepared = false;
       }
    }

Why would i bother to do this? Is this done for consistency of the value between the two threads? if so can i use something like volatile? would that be better?

I ask because i heard that synchronization is expensive. Are there better alternatives?

Thank you all in advance for answering my question. I appreciate it. Edit: I read this synchronization on single statement?

I think i understand.. if someone could elaborate that would be awesome. Also part two of my initial question regarding whether volatile is a better alternative is unanswered :)

Community
  • 1
  • 1
user1953478
  • 705
  • 1
  • 5
  • 8
  • Unless you are writing high-performance, highly multithreaded apps where complex data structures are used from multiple threads, you better forget about "synchronization is expensive". – Chris Jan 07 '13 at 01:36
  • The referenced "synchronization on single statement" thread also answers the volatile portion of your question too. – jco.owens Jan 07 '13 at 01:38
  • "Java 5 Memory Model" links: http://www.cs.umd.edu/~pugh/java/memoryModel/ –  Jan 07 '13 at 05:49

3 Answers3

4

It is done because synchronization also puts in place requirements about memory visibility between threads.

If that write is not synchronized or volatile, there aren't any hard and fast requirements about when it becomes visible to other threads. Another thread could have a copy of isPrepared in its stack that says true, and it could run forever without knowing to go back to main memory and check if someone else has changed isPrepared if there's no synchronization or volatile reference.

The volatile keyword would satisfy the immediate requirement of making sure other threads see the update. It is impossible to say without seeing the entire class/system if it would be an acceptable replacement. It could be that there are other synchronized methods and it is illegal to change the state of isPrepared while one of them is mid-execution. Clearly it would then be an error to remove the synchronization in favour of a volatile reference.

Affe
  • 47,174
  • 11
  • 83
  • 83
  • Affe, Thank you for your answer :)I appreciate it. But how would it be an error? If i have a synchronized block of code/method which has the isPrepared variable wouldn't it run sequentially without the thread getting knocked out. Then i could declare the isPrepared variable as volatile globally and not have to do synchronization in the above methods? is that correct understanding? I see a sense for synchronization in a method where i perform a conditional check and then update (which is what i have elsewhere) can i mix and match in this case? – user1953478 Jan 07 '13 at 07:26
  • If your *only* need is memory visibility, then switching to volatile is fine. I was just saying that I'm not comfortable saying "volatile will do the same thing" without seeing the entire code, since other methods could possibly be written in ways that make the statement not true. You should not mix and match, if any writes involve a conditional, then all writes should be synchronized. (It would be POSSIBLE to write correct code that is partially synchronized, but you're embarking on a road fraught with perils for what gain?) – Affe Jan 07 '13 at 07:36
  • This question + answer also has a simple example demonstrating the problem: http://stackoverflow.com/questions/11570533/java-does-not-follow-code/11570673#11570673 – Affe Jan 07 '13 at 07:38
  • i guess i was thinking that i would improve performance by not using so many synchronized statements. Like if i synchronized it one block of code because i want the block of code to run atomically, i could get away with the same variable being atomic in single line statements and the performance hit i would take would be minimized? Even though i also read that its not noticeable. Maybe the way i understand synchronization is skewed? lol Thanks again Affe. Now if only i was allowed to do vote up as well. – user1953478 Jan 08 '13 at 03:13
  • You probably could, it's just generally advised not to engage in that level of super-specific fine tuning unless it's been proven that the code is a relevant bottle-neck. You may be chasing nano-seconds when something else in the process takes milli-seconds anyway. And sacrificing maintainability, readability, understandability etc etc etc for it. – Affe Jan 08 '13 at 04:04
0

Using volatile on boolean will also work without synchronisation in your case.
A primitive boolean is represented as 4 byte value and would be written in one (assembler) statement.

That is not guaruanteed to work for 8 byte values (e.g long / double) where one thread could write the lower 4 bytes while the other thread writes the upper 4 bytes.

AlexWien
  • 28,470
  • 6
  • 53
  • 83
  • 3
    adding volatile does more than just ensure that the value is not inconsistent between threads. it has important memory effects. and no platform can "ignore" the volatile statement (at least not in java). – jtahlborn Jan 07 '13 at 01:37
  • 1
    That has not been true in like ten years. They fixed volatile longs a long time ago. – Affe Jan 07 '13 at 01:41
  • They? who are they? There is not only sun VM, there is also IBM java 1.3 still used today in embedded devices. – AlexWien Jan 07 '13 at 01:46
  • I removed the part of igbnoring volatile, seems that it cannot be ignored in all java versions. – AlexWien Jan 07 '13 at 01:48
  • 1
    It would be pretty hard to answer a lot of questions if we had to cover every version of the API going back twenty years :) I do think it is misleading to perpetuate "volatile doesn't work for longs" without at least qualifying "on systems running against out of date versions of the language specification." – Affe Jan 07 '13 at 01:57
0

As an addition to previous answers i want to add that in some cases your single line source code can be turned to multiple lines of machine executable code, for example

counter++

Although it might look like a single operation, expression counter++ is actually three separate operations:

1) read counter’s value

2) add 1 to this value

3) store the updated value in counter

So, this kind of statements should be also synchronized in multithreaded contexts.

Suren Aznauryan
  • 984
  • 10
  • 24