(Java synchronization problem)As my title, can I access a static variable in a synchronized block? Will it cause inconsistency ? Can anyone tell me the detail of the disadvantages or advantages of accessing a static variable synchronized block.
can I access a static variable in a synchronized block ?
Yes, You can.
Will it cause inconsistency ?
Static means shared across all the instances of that Class in a JVM. Shared resources are not thread-safe.Hence Static variables are not thread safe.So, if multiple threads tries to access a static variable, it may result in inconsistency.
The ways, which I know of to synchronize access to a static variable.
Synchronize on Static object.
public class SomeClass{
private static int sum = 0;
private static final Object locker = new Object();
public void increaseSum() {
synchronized (locker) {
sum++;
}
}
}
Synchronized Static method.
public class SomeClass {
private static int sum = 0;
public static synchronized void increaseSum() {
sum++;
}
}
Synchronize on class object
public class SomeClass {
private static int sum= 0;
public void increaseSum() {
synchronized (SomeClass .class) {
sum++;
}
}
}
Related
I know that using the synchronize keyword before a method brings synchronization to that object. That is, 2 threads running the same instance of the object will be synchronized.
However, since the synchronization is at the object level, 2 threads running different instances of the object will not be synchronized. If we have a static variable in a Java class that is called by the method, we would like it to be synchronized across instances of the class. The two instances are running in 2 different threads.
Can we achieve synchronization in the following way?
public class Test
{
private static int count = 0;
private static final Object lock= new Object();
public synchronized void foo()
{
synchronized(lock)
{
count++;
}
}
}
Is it true that since we have defined an object lock that is static and we are using the keyword synchronized for that lock, the static variable count is now synchronized across instances of class Test?
There are several ways to synchronize access to a static variable.
Use a synchronized static method. This synchronizes on the class object.
public class Test {
private static int count = 0;
public static synchronized void incrementCount() {
count++;
}
}
Explicitly synchronize on the class object.
public class Test {
private static int count = 0;
public void incrementCount() {
synchronized (Test.class) {
count++;
}
}
}
Synchronize on some other static object.
public class Test {
private static int count = 0;
private static final Object countLock = new Object();
public void incrementCount() {
synchronized (countLock) {
count++;
}
}
}
Method 3 is the best in many cases because the lock object is not exposed outside of your class.
If you're simply sharing a counter, consider using an AtomicInteger or another suitable class from the java.util.concurrent.atomic package:
public class Test {
private final static AtomicInteger count = new AtomicInteger(0);
public void foo() {
count.incrementAndGet();
}
}
Yes it is true.
If you create two instance of your class
Test t1 = new Test();
Test t2 = new Test();
Then t1.foo and t2.foo both synchronize on the same static object and hence block each other.
We can also use ReentrantLock to achieve the synchronization for static variables.
public class Test {
private static int count = 0;
private static final ReentrantLock reentrantLock = new ReentrantLock();
public void foo() {
reentrantLock.lock();
count = count + 1;
reentrantLock.unlock();
}
}
You can synchronize your code over the class. That would be simplest.
public class Test
{
private static int count = 0;
private static final Object lock= new Object();
public synchronized void foo()
{
synchronized(Test.class)
{
count++;
}
}
}
Hope you find this answer useful.
public class ThreadSafe {
private int aField;
public synchronized void setAField(int value) {
aField = value;
}
public synchronized int getAField() {
return aField;
}
}
public class ThreadSafeToo {
private volatile int aField;
public synchronized void setAField(int value) {
aField = value;
}
public int getAField() {
return aField;
}
}
public class DontKnowIfThreadSafeButMostLikelyYes {
private static int aField;
public synchronized void setAField(int value) {
aField = value;
}
public int getAField() {
return aField;
}
}
Questions:
Is DontKnowIfThreadSafeButMostLikelyYes thread-safe?
What would be the preferred idiom and why?
ThreadSafeToo does not need a synchronized method: volatile assignment is atomic and provides visibility guarantees.
DontKnowIfThreadSafeButMostLikelyYes is not thread safe: you need to synchronize reads AND writes to shared variables.
Preferred idiom is subjective, but in your case, the efficient approach is:
public class ThreadSafeToo {
private volatile int aField;
public void setAField(int value) { aField = value; }
public int getAField() { return aField; }
}
Your class DontKnowIfThreadSafeButMostLikelyYes is not thread safe because a static variable is not different from an instance variable from point of synchronization. Besides this the result will not be the same as in the other cases.
Also the second question is opinion based.
As far as I know DontKnowIfThreadSafeButMostLikelyYes is not thread-safe, because 2 threads could set and get aField at the same moment -> problem
There is no difference if you put the static or not. Both would be not thread-safe.
I think there is no real preferred idom. In this case I would choose the first way. But you can also use the second one or you could use locks.
Is DontKnowIfThreadSafeButMostLikelyYes thread-safe?
No, because when getter & setter are being called the same moment getter might return old value.
What would be the preferred idiom and why?
In this case the 2nd class is correctly synchronized & is thread safe
class Bob {
private static final Object locke = new Object();
private static volatile int value;
public static void fun(){
synchronized(locke){
value++;
}
}
}
How is this different from synchronizing on the class, i.e. synchronized(Bob.class){...}
Some other code can break yours by doing a synchronized(Bob.class). If they do, your code suddenly contests with their code for the lock, possibly breaking your code.
That danger is removed if the lock object is not accessible from outside the object that needs it.
What would be the behaviour of the following program where static synchronized method and instance synchronized method is trying to access static field of same class in different threads? Will any thread get blocked? Its very confusing.
class MyClass
{
public static int i = 5;
public synchronized void m1()
{
System.out.println(i); //uses static field i of MyClass
//T1 is executing this method
}
public static synchronized void m3()
{
//T2 will be able to call this method on same object lock while it is using
//static field i???
System.out.println(i);//uses static field i of MyClass
}
}
Synchronized instance methods are equivalent of
public void m1() {
synchronized(this) {
...
}
}
(well, they are not exactly the same, but the answer to your question does not suffer from that difference).
Synchronized static methods are synchronized on the class:
public void m2() {
synchronized(MyClass.class) {
...
}
}
As you can see, two block are synchronized on difference objects: m1 is synchronized on the instance it is called on, and m2 is synchronized on the instance of Class<MyClass> which represents your class in JVM. So those two methods can be called without blocking each other.
You are always synchronizing on an object.
Funciton m1 synchronizes on an instance of an object on which it is called.
Function m3 synchronizes on the class itself.
m1 could be written as:
public void m1()
{
synchronized(this) {
System.out.println(i); //uses static field i of MyClass
//T1 is executing this method
}
}
Therefore you are synchronizing on two different objects and these two methods can acces any global variable concurrently.
Your sample code looks good.
Best way to assure synchronization of static variables according to me is. As lock object is not accessible outside your Class. See below.
public class MyClass
{
private static int i = 0;
private static final Object lockObject = new Object();
public void m1() {
synchronized (lockObject ) {
//Use you static var
}
}
public void m3() {
synchronized (lockObject ) {
//Use you static var
}
}
}
The method m1 and m3 can be executed independently.
Because as you already said static synchronized is on the object. Therefore the same as synchronize(MyClass.class).
synchronized are instance wide usable. So it is only blocked for the instances. It would be the same as using:
MyClass myClass = new MyClass();
synchronize (myClass)
{
.....
}
Java does not have any synchronization controls that relate to accessing static fields.
If you make your methods empty, the synchronization will be exactly the same.
Specifically, as long as any thread is executing any synchronized static method in that type, all other threads that call synchronized static methods will wait for them to finish, so that at most one synchronized static method will be executing at once.
This is a question concerning what is the proper way to synchronize a shared object in java. One caveat is that the object that I want to share must be accessed from static methods. My question is, If I synchronize on a static field, does that lock the class the field belongs to similar to the way a synchronized static method would? Or, will this only lock the field itself?
In my specific example I am asking: Will calling PayloadService.getPayload() or PayloadService.setPayload() lock PayloadService.payload? Or will it lock the entire PayloadService class?
public class PayloadService extends Service {
private static PayloadDTO payload = new PayloadDTO();
public static void setPayload(PayloadDTO payload){
synchronized(PayloadService.payload){
PayloadService.payload = payload;
}
}
public static PayloadDTO getPayload() {
synchronized(PayloadService.payload){
return PayloadService.payload ;
}
}
...
Is this a correct/acceptable approach ?
In my example the PayloadService is a separate thread, updating the payload object at regular intervals - other threads need to call PayloadService.getPayload() at random intervals to get the latest data and I need to make sure that they don't lock the PayloadService from carrying out its timer task
Based on the responses, I refactored to the following:
public class PayloadHolder {
private static PayloadHolder holder;
private static PayloadDTO payload;
private PayloadHolder(){
}
public static synchronized PayloadHolder getInstance(){
if(holder == null){
holder = new PayloadHolder();
}
return holder;
}
public static synchronized void initPayload(){
PayloadHolder.payload = new PayloadDTO();
}
public static synchronized PayloadDTO getPayload() {
return payload;
}
public static synchronized void setPayload(PayloadDTO p) {
PayloadHolder.payload = p;
}
}
public class PayloadService extends Service {
private static PayloadHolder payloadHolder = PayloadHolder.getInstance();
public static void initPayload(){
PayloadHolder.initPayload();
}
public static void setPayload(PayloadDTO payload){
PayloadHolder.setPayload(payload);
}
public static PayloadDTO getPayload() {
return PayloadHolder.getPayload();
}
...
Is this approach legitimate? I am also curious if it is better to do it this way or using the AtomicReference approach mentioned by Hardcoded ...?
- I am keeping an instance of PayloadHolder on PayloadService simply to keep a reference to the PayloadHolder class active in the jvm for as long as the PayloadService is running.
Your code should look like this:
public static void setPayload(PayloadDTO payload){
synchronized(PayloadService.class){
PayloadService.payload = payload;
}
}
public static PayloadDTO getPayload() {
synchronized(PayloadService.class){
return PayloadService.payload ;
}
}
Your original code wouldn't have worked even if the methods weren't static. The reason being is you were synchronizing on the payload instance that you were changing.
Update, a response to johnrock comment:
Locking the whole class is only a problem if you have other synchronized static blocks that you want to run currently. If you want to have multiple independent locked section then I suggest you do something like this:
public static final Object myLock = new Object();
public static void setPayload(PayloadDTO payload){
synchronized(myLock){
PayloadService.payload = payload;
}
}
public static PayloadDTO getPayload() {
synchronized(myLock){
return PayloadService.payload ;
}
}
Or, if you require a more complex concurrency pattern look at java.util.concurrent which has many pre-built classes to aid you.
You could, as mentioned in other posts, synchronize on the class or on an explicit monitor.
There are 2 other ways, if we assume that your are using the sychnronize only for thread-safe getting and setting of the property: volatile and AtomicReference.
volatile
The volatile keyword will make access to the variable atomic, meaning that reading and assigning the variable won't be optimized by the CPUs local registers and are done atomically.
AtomicReference
The AtomicReference is a special class at the java.util.concurrent.atomic package, which allows atomic access to a variable-like reference. It is very similiar to volatile, but gives you some additional atomic operations, like compareAndSet.
Example:
public class PayloadService extends Service {
private static final AtomicReference<PayloadDTO> payload
= new AtomicReference<PayloadDTO>(new PayloadDTO());
public static void setPayload(PayloadDTO payload){
PayloadService.payload.set(payload);
}
public static PayloadDTO getPayload() {
return PayloadService.payload.get ;
}
Edit:
Your Holder seems quite confused, since you are instantiating classes only to call static Methods. A try to get it fixed with AtomicReference:
public class PayloadHolder {
private static AtomicReference<PayloadHolder> holder = new AtomicReference<PayloadHolder();
//This should be fetched through the holder instance, so no static
private AtomicReference<PayloadDTO> payload = new AtomicReference<PayloadDTO>();
private PayloadHolder(){
}
public static PayloadHolder getInstance(){
PayloadHolder instance = holder.get();
//Check if there's already an instance
if(instance == null){
//Try to set a new PayloadHolder - if no one set it already.
holder.compareAndSet(null, new PayloadHolder());
instance = holder.get();
}
return instance;
}
public void initPayload(){
payload.set(new PayloadDTO());
//Alternative to prevent a second init:
//payload.compareAndSet(null, new PayloadDTO());
}
public PayloadDTO getPayload() {
return payload.get;
}
public void setPayload(PayloadDTO p) {
payload.set(p);
}
}
public class PayloadService extends Service {
private final PayloadHolder payloadHolder = PayloadHolder.getInstance();
public void initPayload(){
payloadHolder.initPayload();
}
public void setPayload(PayloadDTO payload){
payloadHolder.setPayload(payload);
}
public PayloadDTO getPayload() {
return payloadHolder.getPayload();
}
}
My question is, If I synchronize on a static field, does that lock the class the field belongs to similar to the way a synchronized static method would? Or, will this only lock the field itself?
No, it just lock in the object itself ( the class attribute not the whole class )
Is this a correct/acceptable approach ?
You could probably take a look at the java.util.concurrent.lock package.
I don't really like synchronizing on a class attribute, but I guess that's just a matter of teste.
Synchronize on another static object that does not change:
public class PayloadService extends Service {
private static PayloadDTO payload = new PayloadDTO();
private static final Object lock = new Object();
public static void setPayload(PayloadDTO payload){
synchronized(lock){
PayloadService.payload = payload;
}
}
public static PayloadDTO getPayload() {
synchronized(lock){
return PayloadService.payload ;
}
}
Is this a correct/acceptable approach ?
No, the reason for this is that you should never synchronize on an variable/field that can change its value. That is, when you synchronize on PayloadService.payload and set a new PayloadService.payload, then you are violating a golden rule of synchronization.
You should either synchronize on the class instance or create some arbitrary private static final Object lock = new Object() and synchronize on that. You will have the same effect as synchronizing on the class.
There is a major part of functionality in this class which isn't posted which contributes to whether or not this approach is thread-safe: how do you access the PayloadDTO instance from the other parts of this class where it is used?
If you are providing methods which could swap in another instance for payload while another thread is running code which uses the payload object, then this is not thread safe.
For example if you have a method execute() which does the main work of this class and invokes methods on payload, you need to make sure that one thread cannot change the payload instance with the setter method while another thread is busy running execute().
In short, when you have shared state, you need to synchronize on all read and write operations on the state.
Personally I don't understand this approach and would never take it - providing static methods to allow other threads to re-configure a class smells like a violation of separation of concerns.