Sometimes we can have a thread changing the state of a primitive type flag, and other threads reading it.
The correct way to proceed is to synchronize that flag using synchronized blocks or defining it as volatile to assure visibility between threads. But what about atomicy?
If we define a variable of a primitive type and make read or write actions over it without synchronizing, supposing that it were visible from other threads, would that operation be atomic? That's to say, if the primitive type is for example an integer (4 bytes), are those 4 bytes written atomically?
The answer is almost a "Yes". Internally, all primitive types but double and long are managed atomically as 4 bytes blocks. That differs from C/C++ where, depending on the platform read and write actions can or cannot be atomic. If we don't synchronize correctly in C/C++ we can read a variable of a primitive type written partially with unexpected results.
What happens with double and long primitive types?
As they are 64 bits types they can be treated by the compiler as two 32 bits read and write operations. Therefore, in case of not being synchronized correctly we could run into those same strange things that might happen in C/C++.
Any other solution besides using synchronized blocks?
Yes, we have the volatile declaration. Besides assuring visibility, if we declare a primitive type as volatile we are also assuring atomicy in read and write actions over it.
Remember that accessing volatile variables are lighter than using synchronized blocks and they never block.
The correct way to proceed is to synchronize that flag using synchronized blocks or defining it as volatile to assure visibility between threads. But what about atomicy?
If we define a variable of a primitive type and make read or write actions over it without synchronizing, supposing that it were visible from other threads, would that operation be atomic? That's to say, if the primitive type is for example an integer (4 bytes), are those 4 bytes written atomically?
The answer is almost a "Yes". Internally, all primitive types but double and long are managed atomically as 4 bytes blocks. That differs from C/C++ where, depending on the platform read and write actions can or cannot be atomic. If we don't synchronize correctly in C/C++ we can read a variable of a primitive type written partially with unexpected results.
What happens with double and long primitive types?
As they are 64 bits types they can be treated by the compiler as two 32 bits read and write operations. Therefore, in case of not being synchronized correctly we could run into those same strange things that might happen in C/C++.
Any other solution besides using synchronized blocks?
Yes, we have the volatile declaration. Besides assuring visibility, if we declare a primitive type as volatile we are also assuring atomicy in read and write actions over it.
Remember that accessing volatile variables are lighter than using synchronized blocks and they never block.
No comments:
Post a Comment