What is the purpose of passing parameter to synchronized block? - java

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());
}
}
}
}

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.
The purpose of the parameter is twofold:
It makes it possible to synchronize other blocks on the same object, so that if you have two blocks of code that may change the state of the same object, they don't interfere with each other.
For example:
public void getSum() {
int sum = 0;
synchronized (this.list) {
for (Thingy t : this.list) {
sum += t.getValue();
}
}
return sum;
}
public void addValue(int value) {
synchronized (this.list) {
this.list.add(new Thingy(value));
}
}
There, it's important that we synchronize both accesses to list across threads. We can't have something calling addValue and stomping on the list while another thread is calling getSum.
It makes it possible to ensure you're synchronizing with the correct granularity. If you're serializing access to an instance-specific resource, then it doesn't make sense to do that across instances; you should allow multiple threads into the block provided they're operating on different instances. That's why you would synchronize on this (or more usually some field of this) for an instance-specific resource, or the class (or more usually some class field) if it were a static resource. Similarly, there's no need to synchronize on this if you only need to protect a specific field of it.
For example:
// (In MyClass)
public void getThingySum() {
int sum = 0;
synchronized (this.thingyList) {
for (Thingy t : this.thingyList) {
sum += t.getValue();
}
}
return sum;
}
public void addThingy(Thingy t) {
synchronized (this.thingyList) {
this.thingyList.add(t);
}
}
public void getNiftySum() {
int sum = 0;
synchronized (this.niftyList) {
for (Nifty n : this.niftyList) {
sum += n.getValue();
}
}
return sum;
}
public void addNifty(Nifty n) {
synchronized (this.niftyList) {
this.niftyList.add(t);
}
}
There, we synchronize access to this.thingyList on this.thingyList, not this or MyClass.class. It's fine if one thread is calling getThingySum while another thread calls addNifty, so synchronizing on this would be overkill.
Re your str example:
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());
}
}
}
The comment there is incorrect, any non-null instance will not adequately protect that code. The reason the above seems to work is string interning: The same String instance is used by all threads, because string literals are automatically put in the string intern pool. (Which means you're over-synchronizing; it's JVM-wide, not instance-specific.) So it works, but not because it's just any object. If you changed it from:
String str = "asd";
to
Object o = new Object();
and synchronized on that, it would do nothing to serialize access to the account.
In your example, the correct thing to synchronize on is this.account.

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.

Also you might need to pass an object of instance X to the parameters of synchronized in case you need to pass it to the waiting queue (by using X.wait()). Then, from another thread you may notify the object (whenever required) by calling notify() on X.

Related

When the getMethod needs to have the lock? I tried several times to put and not put the lock in the get method without seeing changes

// this is just an example to better understand. I would like to understand if it is necessary or not to lock I don't know if this example is suitable for what I want to understand .............................................................................................................................................................................................
class Counter{
int counter;
public ReentrantLock lock=new ReentrantLock();
//if the variable is visible to more Threads all readings and writes must be Thread-safe?
public void incr() {
lock.lock();
try {
counter++;
} finally {
lock.unlock();
}
}
public void decr() {
lock.lock();
try {
counter--;
} finally {
lock.unlock();
}
}
//must have Lock
public int getincr() {
return counter;
}
}
//these are the Thread
public class Worker extends Thread {
private Counter c;
public Worker (Counter c) {
this.c=c;
}
enter code here
public void run() {
System.out.println(Thread.currentThread().getName());
for(int i=1;i<=10;i++) {
c.incr(); System.out.println(c.getincr());//this is the method
c.decr(); System.out.println(c.getincr());
}
try {
Thread.currentThread().sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//Main
public class Test {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
Counter c=new Counter();
Worker[] threads = new Worker[100];
for(int i=0;i<100;i++) {
threads[i]=new Worker(c);
threads[i].start();
//threads[i].join();
}
}
}
Try adding the following two lines to the end of your main method and then adding and removing the locking code.
Thread.sleep(10000);
System.out.println("Final counter value: " + c.counter)
What you will see if you run the main method a few times is the following:
When you don't have the explicit locking around the incrementing and decrementing of the counter, the end value of the counter might be incorrect.
When you have the explicit locking around the counter variable, the final counter value will always be correct (zero) at the end of the test.
An explanation of the above behaviour is that with locking, the value of the counter that is being accessed is always correct. Since both increment and decrement use the same explicit lock object before operating on the counter variable, the JVM guarantees that you will have the latest value of the variable.
Regarding the getincr() in the Counter class, since the value that it accesses and returns might also at the same time be incremented or decremented by another thread (than the one that is doing the reading), you need to acquire a lock in order to ensure that you are reading the latest value of the counter. To quote the authoritative book Concurrency in Practice (section 2.4. Guarding State with Locks):
It is a common mistake to assume that synchronization needs to be used only when writing to shared variables; this is simply not true. For each mutable state variable that may be accessed by more than one thread, all accesses to that variable must be performed with the same lock held. In this case, we say that the variable is guarded by that lock.
Another way of implementing your locking could have been to use a ReentrantReadWriteLock, in which case the Counter class methods incr() and decr() would acquire write locks and the getincr() method would acquire a read lock.
Additionally, since only one operation is performed in each of the Counter methods incr(), decr() and getincr(), you could substitute locking with the use of an AtomicInteger for your counter variable (instead of using an int), which would also provide thread-safe access.

synchronize max value while one thread add items and one thread removes items

I'm implementing a program with ArrayList with Objects called Bicycle in it.
I maintain a variable to save the max Bicycle (measured by its id) and a variable to save the max Bicycle index in the array.
I have implented 2 functions - addBicycle and removeMax and they are synchornized.
I'm worried about what might happen when one thread is in addBicycle and other thread is in removeMax - one might add new bicycle which will be the maximum and the second thread will remove accidently older value which is no longer a maximum.
Is there a way to prevent it? a way to forbid that one thread will be at the add function and the other at the remove function, at the same time?
Thanks
edit: code -
public BicycleDataStructure() {
list = new ArrayList<T>();
maxBicycle = null;
maxBicycleIndex = 0;
}
public synchronized void addBicycle(T bToAdd) {
if (list.size() == 0) {
list.add(bToAdd);
maxBicycle = bToAdd;
maxBicycleIndex = 0;
} else {
for (int i = 0; i < list.size(); i++) {
//checks to add in the right position in the list
list.add(i, bToAdd); }
}
}
public synchronized Bicycle removeMaxBicycle() {
if (list.isEmpty()){
return null;
}
list.remove(maxBicycleIndex);
if (!list.isEmpty()) {
maxBicycle = collection.get(maxBicycleIndex- 1);
maxBicycleIndex-= 1;
}
}
You are using synchronized method on same object lock so it is safe due to below reason
It is not possible for two invocations of synchronized methods on the
same object to interleave. When one thread is executing a synchronized
method for an object, all other threads that invoke synchronized
methods for the same object block (suspend execution) until the first
thread is done with the object.
Second, when a synchronized method exits, it automatically establishes
a happens-before relationship with any subsequent invocation of a
synchronized method for the same object. This guarantees that changes
to the state of the object are visible to all threads.
With your current implementation, it will not work as you expect. The synchronized keyword just prevent that two threads cannot access that block of code at the same time. However what you've got is two different methods and the situation you described might happen.
When you need to synchronize two methods, consider using semaphore:
private static final int MAX_AVAILABLE = 1;
private final Semaphore semaphore = new Semaphore(MAX_AVAILABLE, true);
public Bicycle removeMaxBicycle(){
semaphore.acquire();
//do your critical stuff
semaphore.release();
}
public void addBicycle(T bToAdd) {
semaphore.acquire();
//do your critical stuff
semaphore.release();
}
If you have any doubt in how to use Semaphore in Java, checkout this link: https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.html

Confusion Regarding java threads on same/different objects

public class Computation extends Thread {
private int num;
private boolean isComplete;
public Computation(int nu) {
num = nu;
}
public void run() {
System.out.println("Thread Called is: " + Thread.currentThread().getName());
}
public static void main(String... args) {
Computation [] c = new Computation[4];
for (int i = 0; i < 3; i++) {
c[i] = new Computation(i);
c[i].start();
}
}
}
My Question is in main function we are creating every time a new Computation object on which the thread is being started then why we need to snchrnoized the run method? As we know for every different class object 'this' reference is different so we don't need to synchronize.
Also in another Example:
public class DiffObjSynchronized implements Runnable {
#Override
public void run() {
move(Thread.currentThread().getId());
}
public synchronized void move(long id) {
System.out.print(id + " ");
System.out.print(id + " ");
}
public static void main(String []args) {
DiffObjSynchronized a = new DiffObjSynchronized();
/**** output ****/
// 8 9 8 9
new Thread(a).start();
new Thread(new DiffObjSynchronized()).start();
}
}
Here is second example just like first we create a Thread on 2 different instances of class. Here we synchronize the move() method but by definition:
"two different objects can enter the synchronized method at the same time"
Please share your feedback?
If I understand you correctly, your question is: "Why is the move method synchronized?"
The answer is: it shouldn't be, for two reasons:
It doesn't access any fields, so there is nothing that could be corrupted by having many threads inside that method at once.
Each thread gets a different instance of the object, and thus a different lock. So the synchronized modifier makes no difference. Each thread can still enter its own instance's move method because they have separate locks.
You only need to synchronize when you have some data which is being shared between threads, and at least one thread is modifying that data.
Your threads are operating on different objects since you create a new instance for each thread. The intrinsic lock used by synchronized belongs to the instance. So the synchronized methods entered by your threads are guarded by different locks.
You need to understand how synchronization works.
Threads take a 'lock' on the object on which you are synchronizing when they enter the synchronized block. If you have a synchronized method then in that case the object becomes the 'this' instance. Now, no 2 threads can take a lock on the same object at the same time. object locks are mutex based in philosophy so only once thread can hold the mutex at a time. When the thread holding the lock exits the synchronized method or the block, it releases the mutex and thus the object lock becomes available to other threads to request lock on.
This link explains the concepts excellently. It has pictures about disassembled byte code which shows how threads take and leave locks and why 2 threads on 2 different object dont block each other.

Two threads, two synchronized blocks and one intrinsic lock

I wrote a code snippet that starts two threads; one thread prints all odd numbers while another thread prints all even numbers.
I used a combination of intrinsic lock and thread communication commands to achieve proper interleaving of my two threads.
Here is my code,
public class threadEvenOdd implements Runnable
{
static Boolean isOdd=true;
int count = 10;
Boolean value;
static int c=1;
static Object lock = new Object();
threadEvenOdd(Boolean temp)
{
value = temp;
}
public void run()
{
if(value)
{
printOdd(count);
}
if(!value)
{
printEven(count);
}
}
void printOdd(int count)
{
try
{
for(int i=0;i<count/2;i++)
{
//System.out.println("odd enters lock");
synchronized(lock)
{
if(!isOdd)
{
//System.out.println("odd in barrier");
lock.wait();
}
System.out.println(c);
c++;
isOdd = false;
//System.out.println("odd notifies");
lock.notify();
}
}
}
catch(Exception e)
{
System.out.println(e);
}
}
void printEven(int count)
{
try
{
for(int i=0;i<count/2;i++)
{
//System.out.println("even enters lock");
synchronized(lock)
{
if(isOdd)
{
//System.out.println("even in barrier");
lock.wait();
}
System.out.println(c);
c++;
isOdd = true;
//System.out.println("even notifies");
lock.notify();
}
}
}
catch(Exception e)
{
System.out.println(e);
}
}
public static void main (String args[])
{
threadEvenOdd th1 = new threadEvenOdd(true);
threadEvenOdd th2 = new threadEvenOdd(false);
Thread t1 = new Thread(th1);
t1.setName("odd");
Thread t2 = new Thread(th2);
t2.setName("even");
//System.out.println(t1.getName() + " starts");
t1.start();
//System.out.println(t2.getName() + " starts");
t2.start();
}
}
Here are my questions:
The odd thread executes in the printOdd() function, while the even thread executes in the printEven() function. I am using one intrinsic lock for both threads; I don't understand how the two threads can exist in their respective synchronized blocks at the same time, because the use the same lock.
I removed the thread communication statements(notify, wait) from my code and still I obtained my desired output. I am now wondering if my code actually needs the thread communication statements at all.
I guess I still need to work on my understanding of multithreading concepts, as I am struggling to understand my own code :p Can anyone explain if there is a better way to do this using only the multithreading concepts that I have used?
Each thread has its own path of execution through the code. Even if two threads run the exact same code they still have two distinct execution points through the code execution through the code. When a thread reaches a synchronized statement it waits for the lock to be available - it will enter the synchronized block only if no other thread is inside a synchronized block guarded by the same lock.
You keep getting the same output although you removed the notify/wait statements can be coincidental. Did you try this with a relatively large value of the count field?
It is kind of hard to answer this question at the moment as you didn't specify what output do you expect this program to produce. Is "1,3,5,7,9,2,4,6,8" a valid output? Is "1,3,2,4,6,5,7,9,8"? Or is "1,2,3,4,5,6,7,8,9" the only valid output? That said, here a few quick points:
Use notifyAll() instead of notify
Minimize the state that is shared between threads. In this case, you share both isOdd and c. Note that the former can be computed from the latter via c % 2 == 1. Thus you can have the thread computing oddness instead of maintaining it as a piece of shared data.
Instead of sharing via static fields create an object (with instance fields) and pass this object to the constructor of each thread. Then you can use the object itself as a lock.
Here's how it can look like:
class SharedData {
int c;
boolean isOdd;
}
class ThreadEvenOdd {
SharedData sharedData;
public ThreadEvenOdd(SharedData sd) { this.sharedData = sd }
// ...
void printOdd(int count) {
try {
for(int i=0;i<count/2;i++) {
synchronized(sharedData) {
if(!sharedData.isOdd) { ... }
System.out.println(sharedData.c);
sharedData.c++;
sharedData.isOdd = false;
lock.notify();
}
}
}
catch(Exception e) {
System.out.println(e);
}
}
}
The nice thing about it is that you can then start defining real methods on sharedData (such as: a method that increases c and set isOdd to the appropriate value based on the value of c thus further simplifying the code in the thread class - and making the synchronization/notification less interleaved with the processing of the data, which makes the code more readable and less prone to errors.

Java Object Construction In Multi-Threaded Environment

I am reading this book called "Java Concurrency in Practice" and the author gives an example of an unsafe object publication. Here is the example.
public Holder holder;
public void initialize(){
holder = new Holder(42);
}
and
public class Holder {
private int n;
public Holder(int n) { this.n = n; }
public void assertSanity() {
if (n != n)
throw new AssertionError("This statement is false.");
}
}
So does this mean that other thread has access to an object when it is not even fully constructed? I guess that when a thread A calls holder.initialize(); and thread B calls holder.assertSanity(); the condition n != n will not be met if thread A has not yet executed this.n = n;
Does this also mean that if I have a simpler code like
int n;
System.out.println(n == n); //false?
A problem can occur if the assertSanity method is pre-empted between the first and second load of n (the first load would see 0 and the second load would see the value set by the constructor). The problem is that the basic operations are:
Allocate space for the object
Call the constructor
Set holder to the new instance
The compiler/JVM/CPU is allowed to reorder steps #2 and #3 since there are no memory barriers (final, volatile, synchronized, etc.)
From your second example, it's not clear if "n" is a local variable or a member variable or how another thread might be simultaneously mutating it.
Your understanding is correct. That is exactly the problem the author seek to illustrate. There are no guards in Java that ensure an object is fully constructed prior to accessing in when multiple threads are concerned. Holder is not thread-safe as it contains mutable state. The use of synchronization is required to fix this.
I'm not sure I understand your 2nd example, it lacks context.
public static void main(String[] args) {
A a = new A();
System.out.println(a.n);
}
static class A{
public int n;
public A(){
new Thread(){
public void run() {
System.out.println(A.this.n);
};
}.start();
try {
Thread.currentThread().sleep(1000);
n=3;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
This example result in "0 3" which means reference to an object could be used by another thread even before its constructor done. You may find the rest answer here. Wish it could help .

Categories