Why synchronize on a static lock member rather than on a class? - java

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.

Related

Visibility of mutable object under different locks in Java

mFeaute is a mutable object.
I want to know if the change of mFeature in setFeature(Feature feature) is visible to mFeature in useFeature(...) with a different explicit form of synchronized.
Thanks.
public class FeatureService {
private static Feature mFeature= null;
private final Object MUTEX = new Object();
...
static void setFeature(Feature feature){
// doSomething
synchronized (FeatureService.class){
mFeature = feature;
// doSomething
}
// doSomething
}
public void useFeature(...){
// doSomething
synchronized (MUTEX){
someFunction(mFeature);
// doSomething
}
// doSomething
}
}
}
The above code is suffering from a data race and hence is broken. You do not have a happens before edge between the write and the read of mfeature because different locks are used. You need to use the same lock instance for both reading and writing.
It is unclear what you are trying to synchronize on (ClassA and ObjectB are vague). In general, you want to synchronize on a single mutex when interacting with a given shared resource. Create an Object to serve as the mutex upon which you synchronize when accessing the internal mFeature.
public class FeatureService {
private static Feature mFeature= null;
private static final Object MUTEX = new Object();
...
static void setFeature(Feature feature){
synchronized (MUTEX){
mFeature = feature;
}
}
public void useFeature(...){
synchronized (MUTEX){
someFunction(mFeature);
}
}
}

Some case-specific questions about multi-threading

Question 1.
If we consider the following class:
public class Test {
public static LinkedList<String> list;
}
How would you make getting/setting thread-safe for the variable 'list'?
I guess I could do something like this:
public class Test {
private static LinkedList<String> list;
public static synchronized LinkedList<String> getList() {
return new LinkedList<>(list);
}
public static synchronized void setList(LinkedList<String> data) {
list = new LinkedList<>(data);
}
}
Question 2.
But how thread-safe is this? Would I have to initialize a new list each time to ensure other copies don't affect the variable?
Question 3.
If we consider this instead:
public class Test {
private static LinkedList<String> list;
public static synchronized void ManipulateList() {
// do stuff to 'list'
}
public static synchronized void ChangeList() {
// do more stuff to 'list'
}
}
where both methods 'ManipulateList' and 'ChangeList' might add or remove variables to the same list
Is this thread-safe? Does this mean that if thread 1 is accessing 'ManipulateList' then thread 2 is not able to access 'ChangeList' until thread 1 finishes accessing 'ManipulateList'?
I'm just not sure if I'm understanding the effects correctly.
Question 1.
public static LinkedList<String> list;
How would you make getting/setting thread-safe for the variable
'list'?
Avoid global [mutable] state. Just get rid of it.
Question 2.
public class Test {
private static LinkedList<String> list;
public static synchronized LinkedList<String> getList() {
return new LinkedList<>(list);
}
public static synchronized void setList(LinkedList<String> data) {
list = new LinkedList<>(data);
}
}
But how thread-safe is this? Would I have to initialize a new list
each time to ensure other copies don't affect the variable?
(I am going to assume by this you mean Test.list not the passed in data which, due to the defects of the Java collection library, is mutable itself.
So you are always accessing the list with the same lock held. You are always copying the list when dealing with the outside world. The members of the list are immutable, so you don't need any deep copying. All good.
The method have the lock held over an expensive operation not involving the variable, so we should do better here.
public static synchronized LinkedList<String> getList() {
// The `LinkedList` list points to is never mutated after set.
LinkedList<String> local;
synchronized (Test.class) {
local = list;
}
return new LinkedList<>(local);
}
public static void setList(LinkedList<String> data) {
LinkedList<String> local = new LinkedList<>(data);
synchronized (Test.class) {
list = local;
}
}
In theory, even without the change the lock needn't be held continuously for the entire copy. As it is a public lock object (but naughty, but common) data could wait on it releasing the lock temporarily. Obviously not significant here, but in real world cases it may lead to strangeness.
Slightly more obscurely, list could be made volatile and the lock elided.
Question 3.
private static LinkedList<String> list;
public static synchronized void ManipulateList() {
// do stuff to 'list'
}
public static synchronized void ChangeList() {
// do more stuff to 'list'
}
Is this thread-safe? Does this mean that if thread 1 is accessing
'ManipulateList' then thread 2 is not able to access 'ChangeList'
until thread 1 finishes accessing 'ManipulateList'?
Yes. Other than there may be waits and one of the methods could call the other, perhaps indirectly.
General notes.
Remove global [mutable] state.
Try to avoid shared mutable object (keep shared object immutable and mutable objects unshared).
Reduce the amount of code and time that locks are held for.
Copy mutable inputs and outputs.
I guess I could do something like this:
This isn't thread safe.
Specifically, the setter:
public static synchronized void setList(LinkedList<String> data) {
list = new LinkedList<>(data);
}
does not enforce that data is accessed exclusively for the duration of the setList method. As such, other threads could modify the list during the implicit iteration.
The code in question 3 is fine with respect to updates to the list, because the fact the methods are synchronized means that the list is accessed mutually exclusively, and the effects of one method invocation are visible to subsequent invocations.
But it's not entirely safe, because nefarious code can acquire (and hold onto) the monitor of Test, which could lead to a deadlock.
You can fix this specific issue by having an explicit monitor that can only be acquired inside the class:
class Test {
private final Object obj = new Object();
public static void ManipulateList() {
synchronized (obj) { ... }
}
public static void ChangeList() {
synchronized (obj) { ... }
}
}
Anything that subclasses your Test class could break your synchronization scheme because subclasses could directly access the list without the method-synchronization - either by subclassing your Test class or through reflection.
public class MyTestClass extends Test {
// blah...
public static changeTheList() {
this.list.add("Bypasses synchronization through direct access to the list.");
}
}
A better solution for synchronization is to initialize your list with a synchronized wrapper, like this:
public class Test {
private static LinkedList<String> list = Collections.synchronizedList(new LinkedList<>());
public static synchronized LinkedList<String> getList() {
return list;
}
public static synchronized void setList(LinkedList<String> newList) {
list = newList;
}
}
In the second snippet, you can now safely sub-class your Test class and access the list in a thread-safe manner because the list itself is synchronized.
You other option is to mark your Test class as final but you would still need to fix your implementation (you re-initialize the list in your getter's & setter's which is not a good idea).
Also -- I might suggest you look at some tutorials regarding synchronization -- a couple of suggestions:
https://www.baeldung.com/java-synchronized-collections
https://howtodoinjava.com/java/collections/arraylist/synchronize-arraylist/

Class level locking in java

Suppose I have a class on which I want to obtain class level lock. Do I necessarily need to have static methods inside the class to achieve the class level locking or by simply using synchronized(MyClass.class) will do the job without any static methods in it.
Synchronizing on the Class object will do the trick.
Alternatively, if you want your class-level lock to not interfere with a different class-level lock on the same class, then declare a private static field to be the lock; e.g.
public class MyClass {
private static final Object myLock = new Object();
private static final Object anotherLock = new Object();
...
}
Now we have two distinct "class-level" locks for the same class.
You can use ReentrantLock as well:
private static final Lock lock1 = new ReentrantLock();
public static void main(String... strings) {
lock1.lock();
//do Something
lock1.unlock();
}

Acquiring inner-class lock using outer-class locks?

I have an outer class A and that has a public inner class, the structure is as follows -:
public class A{
public int x;
public class B{
private static final int y;
}
public synchronized int method1(){
return x+ B.y;
}
}
the question is if I used synchronized keyword on every method of the class A will it also lock the members of the inner class as well?
if I used synchronized keyword on every method of the class A will it also lock the members of the inner class as well?
No it won't.
You seem to be confused in a number of respects here.
Using a primitive mutex (e.g. via a synchronized method) only locks against other threads that are synchronizing on the same mutex.
When you call a synchronized instance method, the mutex you are acquiring is the mutex for this ... the target object.
In your example, it seems that you want to lock a static field, not an instance field.
If I understand correctly what you are trying to do, the correct way to do it is something like this:
public synchronized int method1(){
synchronized (B.class) {
return x + B.y;
}
}
Note that this involves acquiring two mutexes, so you need to make sure that your code always acquires them in the same order. (If you don't, then there is a risk of deadlocks.)
You would get the same effect if you created and called a synchronized static method on B for getting the value of the y field.
No, the inner class and outer class are two different class objects, they will not be the same. I suggest creating a field in the outer class to manually synchronize on.
An example with a single mutex on 2 objects. Both Objects can change a variable x.
public class A {
private Object mutex = new Object();
private int x;
private B b = new B();
public class B {
private int y;
public int method() {
synchronized(mutex) {
return x++;
}
}
}
public int method() {
synchronized(mutex) {
return x += b.y;
}
}
}

Singleton with initializing a static member

In the code snippet below when I originally designed it, the "next number" needed to send the next incremented value throughout the execution of the application. So I made the class a singleton. However, with some recent change in requirements I needed to do a reset on the "next number". I just added a reset method to do that. However, it definitely violates the Singleton pattern and also I know it is not a good idea to initialize a static member this way.
What do you think I should do instead?
public final class GetNextNumber {
private static GetNextNumber instance;
private static Integer nextNumber=1;
private GetNextNumber() {
}
public static synchronized GetNextNumber getInstance() {
if(instance==null){
instance = new GetNextNumber();
}
return instance;
}
protected Integer getNextNumber(){
return nextNumber++;
}
protected synchronized void reset(){
nextNumber=1;
}
public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
}
why aren't the fields just instance variables? theres no need for static here.
reset doesn't need to be synchronized either, unless getNextNumber is as well.
Looks OK to me - except for two things:
getNextNumber is not synchronized.
since getNextNumber and reset are not static, nextNumber doesn't need to be static, either.
You could use an AtomicInteger to avoid having to make your getNextNumber and reset methods synchronized:
public final class GetNextNumber {
private static GetNextNumber instance;
private AtomicInteger nextNumber = new AtomicInteger(1);
private GetNextNumber() {
}
public static synchronized GetNextNumber getInstance() {
if(instance==null){
instance = new GetNextNumber();
}
return instance;
}
protected Integer getNextNumber(){
return nextNumber.getAndIncrement();
}
protected void reset(){
nextNumber.set(1);
}
}
For futher discussion on this, see for example The Atomic classes in Java 5: AtomicInteger and AtomicLong:
Before Java 5, we had to write classes
with access to the counter variable in
synchronized blocks or methods, or
else use a volatile variable which is
a lighter form of synchronization but
with the risk that some updates could
be missed if they happen concurrently.
An AtomicInteger can be used as a
drop-in replacement that provides the
best of both worlds...

Categories