Why do we use private mutex?
You may see something like this:
public class ValueHolder {
private int a;
private final Object mutex = new Object();
public int getA() {
return a;
}
public void increment() {
synchronized (mutex) {
a++;
}
}
}
And you start wondering: “Hey, why do we use synchronized (mutex)
, can’t we just use synchronized (this)
and everything would work?” Let’s see this in a practical example. Multiple threads will update the state of our ValueHolder
.
The thread that will increment our counter 1000 times:
public class UpdaterThread implements Runnable {
private ValueHolder valueHolder;
public UpdaterThread(ValueHolder valueHolder) {
this.valueHolder = valueHolder;
}
@Override
public void run() {
for (int i = 0 ; i < 1000; i++) {
valueHolder.increment();
}
}
}
Starting 10 threads to update our counter:
public class Main {
public static void main(String[] args) {
List<Thread> threads = new ArrayList<>();
ValueHolder valueHolder = new ValueHolder();
for(int i = 0 ; i < 10 ; i++ ) {
Thread thread = new Thread(new UpdaterThread(valueHolder));
thread.start();
threads.add(thread);
}
}
}
In this case, both mutex
and this
works fine as a lock. But here is where the problem lies:
public class EvilThread implements Runnable {
private final ValueHolder valueHolder;
public EvilThread(ValueHolder valueHolder) {
this.valueHolder = valueHolder;
}
@Override
public void run() {
try {
synchronized (valueHolder) {
Thread.sleep(20000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Start an evil thread and then threads that increments the counter:
public class Main {
public static void main(String[] args) {
List<Thread> threads = new ArrayList<>();
ValueHolder valueHolder = new ValueHolder();
Thread evilThread = new Thread(new EvilThread(valueHolder));
evilThread.start();
for(int i = 0 ; i < 10 ; i++ ) {
Thread thread = new Thread(new UpdaterThread(valueHolder));
thread.start();
threads.add(thread);
}
}
}
EvilThread
holds valueHolder
lock. Now, if inside UpdaterThread
we use this
as a lock then we use the same lock as the EvilThread
and we will have to wait. If we use mutex
, then we don’t have to wait for EvilThread
since the lock is not the same.
Conclusion
We have more control by using private mutex. Also, we can see all the places where the lock is used inside the class. If we use this as a lock, we would need to search the whole project to see where that lock is used.
Further reading
If this article was interesting to you, here are some great resources on the multithreading topic: