I know that when you synchronize a block of code, you specify which object's lock you want to use as the lock, so you could, for example, use some third-party object as the lock for this piece of code. That gives you the ability to have more than one lock for code synchronization within a single object.
However, I don't understand the need of passing argument to the block. Because it doesn't matter whether I pass String's instance, Some random class's instance to the synchronized block as the synchronized block works perfectly irrespective of the parameter being passed to the block.
So my question is if anyways synchronized block stops two threads from entering the critical section simultaneously. Then why there is a need of passing an argument. (I mean acquire lock on some random object by default).
I hope I framed my question correctly.
I have tried the following example with random parameters being to the synchronized block.
public class Launcher {
public static void main(String[] args) {
AccountOperations accOps=new AccountOperations();
Thread lucy=new Thread(accOps,"Lucy");
Thread sam=new Thread(accOps,"Sam");
lucy.start();
sam.start();
}
}
Using non-static synchronized block:
public class AccountOperations implements Runnable{
private Account account = new Account();
public void run(){
for(int i=0;i<5;i++){
makeWithdrawal(10);
}
}
public void makeWithdrawal(int amount){
String str="asd"
synchronized (str /* pass any non-null object the synchronized block works*/) {
if(account.getAmount()>10){
try{
Thread.sleep(5000);
}catch(InterruptedException e){
e.printStackTrace();
}
account.withdraw(amount);
System.out.println(Thread.currentThread().getName()+" has withdrawn 10, current balance "+ account.getAmount());
}else{
System.out.println("Insufficient funds "+account.getAmount());
}
}
}
}
Using static synchronized block:
public class AccountOperations implements Runnable{
private static Account account = new Account();
public void run(){
for(int i=0;i<5;i++){
makeWithdrawal(10);
}
}
public static void makeWithdrawal(int amount){
synchronized (String.class /* pass any class literal synchronized block works*/) {
if(account.getAmount()>10){
try{
Thread.sleep(5000);
}catch(InterruptedException e){
e.printStackTrace();
}
account.withdraw(amount);
System.out.println(Thread.currentThread().getName()+" has withdrawn 10, current balance "+ account.getAmount());
}else{
System.out.println("Insufficient funds "+account.getAmount());
}
}
}
}
if anyways synchronized block stops two threads from entering the critical section simultaneously. Then why there is a need of passing an argument?
Synchronized block decides which threads to stop based on the object that you pass to it. The object that you pass serves as the identifier of the monitor section guarded by the synchronized block.
You may have many monitor sections in your program, all of which could be executed concurrently with each other. For example, if you have two unrelated collections that must be accessed concurrently, you can set up separate monitor sections for each collection. This way threads would be stopped only when other threads are already accessing the same collection; two different threads accessing two different collections would be allowed to proceed concurrently.
Your first example is non-trivial. The reason it works is that the string object is initialized to a string literal. Due to literal's interning, all threads entering the function will obtain the same String
object, so the synchronized block will properly guard the monitor section.