What will be if reassign reference to lock object inside synchronization block? - java

NOTE: Invalid question - see comment of #Bukhtoyarov Vladimir
Let's say we have the following code:
public class Main {
private Object monitor = new Object();
public static void main(String[] args) throws InterruptedException {
Main main = new Main();
main.test();
new Thread() {
#Override
public void run() {
try {
main.changeMonitor();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
private void test() throws InterruptedException {
synchronized (monitor) {
Thread.sleep(100);
monitor = new Object();
Thread.sleep(1000);
System.out.println("test finished");
}
}
private void changeMonitor() throws InterruptedException {
Thread.sleep(600);
monitor = new Object();
System.out.println("monitor changed");
}
}
Here we have two threads - main thread and another worker thread. Also we have monitor object. Inside worker thread we have next sequence of actions -
acquire lock on monitor
wait 100ms
assign monitor reference to point a new object
wait another 1000ms
In main thread we are waiting 600ms and try to reassign monitor to a new object.
As the result - main thread is blocked - till worker thread releases lock on the monitor object.
Here i have two questions
According to the Concurrency in practice book - the only way to be blocked by the lock aquision process - is to enter synchronization block. So why main thread is blocked till worker thread releases lock - in main thread we are not trying to enter synchronization block
Worker thread assign new object to monitor reference after 100ms, why main thread can not acquire lock on new reassigned object after 600ms ? I mean - after 600ms in monitor ref is new object - so lock should be ready to be gained
The behavior is interesting - as i can not find any information about it in official Oracle docs or Concurrency in practice book.

This code
synchronized (monitor) {
is like
Object m = monitor;
synchronized (m) {
i.e. the read only happens once, and in a context which is not thread-safe.
why main thread can not lock on new object - reassigned inside worker thread.
This means
once it has obtained an object to lock on to, it doesn't keep reading the latest value in a loop to see if it can lock on another object.
even if the reference is changed before the read, it could see an old value, as the read is not thread safe.

Related

Threads logic in Java

I'm trying to resolve a university exercise. The class AImpl has a method ma(B b) that creates and runs two threads. These threads have to call mb1() and mb2() (they are simple methods that just print a text, so I didn't include them). The calling thread should then wait for mb1() to terminate before finishing.
My logic is:
The first thread enters and after finishing the execution of b.mb1() starts to wait() on the current object, releasing the mutex. Then the second thread runs and it does the same. When they are both waiting, the calling thread calls notifyAll() on the object, waking both of them. They execute b.mb2() and then terminate.
The problem is that when the first thread starts waiting with object.wait(), the control flow doesn't return on the calling thread and the program enters in a deadlock.
Where is my logic flawed?
public class AImpl{
public static Object object = new Object();
public static void main(String[] args) throws InterruptedException {
BImpl b = new BImpl();
AImpl.ma(b);
}
public static void ma(B b) throws InterruptedException {
Thread thread = new Thread() {
#Override
public void run() {
b.mb1();
synchronized(object){
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
b.mb2();
System.out.println("Thread finished");
}
};
Thread thread1 = new Thread() {
#Override
public void run() {
b.mb1();
synchronized(object){
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
b.mb2();
System.out.println("Thread finished");
}
};
thread.run();
thread1.run();
synchronized(object){
object.notifyAll();
}
System.out.println("Program finished.");
}
}
The notify/notifyAll methods tell the scheduler to notify one/all of the threads currently waiting on the lock that notify or notifyAll was called on. But if a thread hasn't started waiting yet then it doesn't get notified.
The solution is to introduce a condition variable that keeps wait from being called if the notifying has happened already. Define it in the same scope as your lock:
public static volatile boolean ready = false;
Then use it to guard the wait block, like this:
while (!ready) {
object.wait();
}
The code calling notify/notifyAll needs to set the variable (it doesn't matter what order you do it in because the notification doesn't happen until the lock is released):
synchronized (object) {
ready = true;
object.notifyAll();
}
What happens:
If the waiting thread gets to the waiting part before the notifying thread does its notifying, then the waiting thread finds ready is false, so it enters the wait method, releases the lock, and stays there. Then the notifying thread changes the flag to true and wakes up the waiting thread, which can leave the wait, reacquire the lock, and then leave the loop now that the flag is set.
But if the notifying thread does its notify before the other thread waits, that's ok, because the ready flag now prevents the thread from entering the wait, it can skip over it.
Further reading: https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html

Singelton pattern with multithread

I read about sigelton pattern with multithreads and I found that is implemented use synchronized .
my question is can I use wait() + notify() or notifyAll() instead synchronized ??
and if yes which better synchronized or wait()+ notifyAll() ???
The methods wait and notify are only meaningful within a synchronized method/block.
Try this:
public static void main(String[] args) {
Object monitor = new Object();
try {
monitor.wait();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
It will result in:
Exception in thread "main" java.lang.IllegalMonitorStateException
at java.base/java.lang.Object.wait(Native Method)
at java.base/java.lang.Object.wait(Object.java:328)
This is because the current thread does not own the monitor.
Now try this, and you're in business (although not a very useful business yet):
public static void main(String[] args) {
Object monitor = new Object();
synchronized (monitor) {
try {
monitor.wait();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
The thread now waits indefinitely for the notify that will never come.
Now try this:
public static void main(String[] args) {
Object monitor = new Object();
Thread a = new Thread(() -> {
try {
System.out.printf("Thread %s Waiting for notification%n", Thread.currentThread().getId());
synchronized (monitor) {
monitor.wait();
}
System.out.printf("Thread %s Received notification%n", Thread.currentThread().getId());
}
catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread b = new Thread(() -> {
try {
System.out.printf("Thread %s Sleeping three seconds%n", Thread.currentThread().getId());
Thread.sleep(3000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("Thread %s Sending notification%n", Thread.currentThread().getId());
synchronized (monitor) {
monitor.notify();
}
});
a.start();
b.start();
}
Thread a synchronizes on the monitor and waits for a notification.
Thread b sleeps for three seconds, then synchronizes on the monitor and notifies.
Example output:
Thread 14 Waiting for notification
Thread 15 Sleeping three seconds
Thread 15 Sending notification
Thread 14 Received notification
The numbers are the thread ID's which I logged for clarity.
Now to your question about a singleton. There are several ways to enforce that there is only one instance of a class. Most commonly, a framework like Spring enforces single instances of its beans within the application context. This is an accept pragmatic approach. To enforce a singleton within a class loader, probably the best way is to use an enum because it avoids serialization issues, but it's often done with a private constructor and a static instance field. Note that this type of self-managed singletons is considered an anti-pattern by most.
A singleton is normally only unique within a class loader. If you are running on an application server there might be multiple class loaders so you have to be careful there about the context in which you want to be able to use this singleton. In such a situation it might be better to avoid the singleton and instead create a separate deployable service or repository to keep the data in.
If you do have a singleton and want to be able to access it in a thread-safe manner, you will have to synchronize all access to it. You don't necessarily need wait/notify for this. For example:
static long start = System.currentTimeMillis();
public static void main(String[] args) {
Object monitor = new Object();
Thread a = new Thread(() -> {
sleep(1000);
log("before synchronized block");
synchronized (monitor) {
log("entered synchronized block");
log("done");
}
});
Thread b = new Thread(() -> {
log("before synchronized block");
synchronized (monitor) {
log("entered synchronized block");
sleep(3000);
log("done");
}
});
a.start();
b.start();
}
private static void sleep(int millis) {
try {
log("sleeping for " + millis);
Thread.sleep(millis);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
private static void log(String message) {
System.out.printf("At %s thread %s %s%n", (System.currentTimeMillis() - start), Thread.currentThread().getId(), message);
}
Example output:
At 2 thread 15 before synchronized block
At 14 thread 15 entered synchronized block
At 25 thread 14 sleeping for 1000
At 25 thread 15 sleeping for 3000
At 1038 thread 14 before synchronized block
At 3038 thread 15 done
At 3039 thread 14 entered synchronized block
At 3040 thread 14 done
Just by using synchronized already the access can be made exclusive. Only when a thread needs the results of another thread does wait/notify come into play.
can I use wait() + notify() or notifyAll() instead synchronized?
The answer is the same regardless of whether you are trying to implement a singleton or implement anything else.
No.
synchronized is a mechanism by which threads in a Java program can safely share variables. It provides two things:
It prevents threads from interfering with each other when they access the shared variables.
It ensures that updates to shared variables made by one thread will become visible to other threads in a predictable and timely way.
wait(), notify(), and notifyAll() are a mechanism by which one thread can notify other threads that it has changed shared variables in some particular way.
wait() or notify() or notifyAll() don't technically require the use of synchronized, but the Java language designers arbitrarily added that requirement as a reminder that, if you're going to notify another thread about something you did to shared variables, or even if you're only going to look at something that another thread did to them, you're going to need synchronized to safely access the variables.

Understanding deadlock with a simple example

I am working on understanding deadlock basics so I came up with below code. I have two threads acquiring locks in opposite order but they're not deadlocking. When I run it I see all the printouts. What am I doing wrong?
public class DeadlockBasics {
private Lock lockA = new ReentrantLock();
private Lock lockB = new ReentrantLock();
public static void main(String[] args) {
DeadlockBasics dk = new DeadlockBasics();
dk.execute();
}
private void execute() {
new Thread(this::processThis).start();
new Thread(this::processThat).start();
}
// called by thread 1
public void processThis() {
lockA.lock();
// process resource A
System.out.println("resource A -Thread1");
lockB.lock();
// process resource B
System.out.println("resource B -Thread1");
lockA.unlock();
lockB.unlock();
}
// called by thread 2
public void processThat() {
lockB.lock();
// process resource B
System.out.println("resource B -Thread2");
lockA.lock();
// process resource A
System.out.println("resource A -Thread2");
lockA.unlock();
lockB.unlock();
}
}
First of all there is no garantee which threads is start first. To get the deadlock one of the thread has to take a lock on lockA and then the second thread has to take a lock on lockB or visa versa.
public void processThis() {
lockA.lock();
// here the control should be switched to another thread
System.out.println("resource A -Thread1");
lockB.lock();
...
But there may not be enough time to switch between thread because you have just a few lines of code.. It is too fast. To emulate some long work add delay before the second lock to both methods
lockA.lock();
Thread.sleep(200); // 200 milis
Then the second thread will be able to lock lockB before the first release both of them
This could indeed result in a deadlock but not always, for example if the processThis() is completely executed and then the processThat() or vice versa there is no deadlock. You can try to add a Thread.delay(100) or a Thread.yield() to steer the threads execution towards the deadlock or even removing the unlocks to a certain deadlock.
Your code is a good example of dead lock, since ReenttrantLock is a mutual exclusion lock with same behavior as the implicit monitor lock access by using synchronized. However you don't see the deadlock because of this part:
private void execute() {
new Thread(this::processThis).start();
new Thread(this::processThat).start();
}
After the first thread is created and started, it will takes a while to create the second thread. It takes the JVM about 50 us or maybe even less to create a new thread, it sounds very short, but it is enough for the first thread to be finished and therefore a dead lock will not happen.
I added a Thread.sleep(); into your code so the both threads could be executed somehow parallely.
package com.company;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class DeadlockBasics {
private Lock lockA = new ReentrantLock();
private Lock lockB = new ReentrantLock();
public static void main(String[] args) {
DeadlockBasics dk = new DeadlockBasics();
dk.execute();
}
private void execute() {
new Thread(this::processThis).start();
new Thread(this::processThat).start();
}
// called by thread 1
private void processThis() {
lockA.lock();
// process resource A
try {
Thread.sleep(1000); //Wait for thread 2 to be executed
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread 1 will own lock a");
lockB.lock();
// process resource B
System.out.println("Thread 1 will own lock b");
lockA.unlock();
lockB.unlock();
// Both locks will now released from thread 1
}
// called by thread 2
private void processThat() {
lockB.lock();
// process resource B
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread 2 will own lock b");
lockA.lock();
// process resource A
System.out.println("Thread 2 will own lock a");
lockA.unlock();
lockB.unlock();
// Both locks are released by thread 2
}
}
Two points:
Release locks in the reverse order of acquiring them. That is, processThis should reverse the order of removing the locks. For your example, the order doesn't matter. But if processThis attempted to acquire a new lock on A before releasing the lock on B a deadlock could again occur. More generally, you'll find it easier to think about locks by considering their scope and by avoiding overlapping but non-enclosing scopes.
To better highlight the problem, I would put in call to wait after acquiring the first lock in each of threads, and have execute launch both threads then invoke notify on both threads.

Notification in thread

Will the thread give up the monitor immediately as soon as the notify() method is invoked like as it happens in wait(). Or when the notify() is invoked, will the monitor be released after the execution of the method is completed.
To which state will the thread move into when notify() is invoked. Waiting or Blocked state ?
The thread owning the monitor will continue to hold the monitor in case of notify().
notify()/notifyAll() just informs waiting thread that they can optain the lock again. Once a thread obtains the monitor it will exit the wait() method and continue.
To sum up: Thread involving notify()/notifyAll() will stay on RUNNING state as soon as the lock releases naturally (out of synchronized block/method).
The goal of notification is just to authorize waiting threads a future chance to get the lock as soon as this one is available.
A thread holds the monitor for an object as long as it is synchronized on that object. A notified thread will move to the BLOCKED state, and will obtain the monitor once the owning thread releases it by leaving the synchronized block/method that previously held the monitor.
For example, if thread A is blocking on a call to lock.wait() and thread B calls lock.notify(), thread A will leave the WAITING state and enter the BLOCKING state**, however thread A will not resume execution (i.e. enter the RUNNABLE state) until thread B leaves the synchronized block for lock.
** Assumes there are no other threads waiting on lock since the order that threads are notified is not guaranteed, which is why you should use notifyAll() as a rule (unless you know what you're doing and have a good reason not to).
Using code:
public class ThreadStateTest {
private static final Object lock = new Object();
public static void main(String[] args) {
synchronized (lock) {
new Thread(new RunnableTest()).start();
try {
Thread.sleep(1000);
System.out.println("this will print first");
lock.wait();
System.out.println("this will print third");
} catch (InterruptedException ex) {
}
}
}
private static class RunnableTest implements Runnable {
#Override
public void run() {
try {
synchronized (lock) {
lock.notifyAll();
Thread.sleep(1000);
System.out.println("this will print second");
}
Thread.sleep(1000);
System.out.println("this will print fourth");
} catch (InterruptedException ex) {
}
}
}
}

Reentrant lock and deadlock with Java

Can someone explain to me how Reentrant lock and deadlock relate to each other with Java code (pseudo) example?
A reentrant locking mechanism allows the thread holding the lock to re-enter a critical section. This means that you can do something like this:
public synchronized void functionOne() {
// do something
functionTwo();
// do something else
// redundant, but permitted...
synchronized(this) {
// do more stuff
}
}
public synchronized void functionTwo() {
// do even more stuff!
}
In a non-reentrant lock, you would have a deadlock situation when you try to call functionTwo() from functionOne() because the thread would have to wait for the lock...which it holds itself.
Deadlock, of course, is the evil situation in which Thread 1 holds lock A and is waiting for lock B while Thread 2 holds lock B and is waiting for lock A. Thus, neither can continue. This code sample creates a deadlock:
public synchronized void deadlock() throws InterruptedException {
Thread th = new Thread() {
public void run() {
deadlock();
}
}.start();
th.join();
}
The calling thread tries to wait around for the spawned thread, which in turn can't call deadlock() until the caller has exited. Ka-boom!
A deadlock occurs when a thread waits for a condition which will never become true.
The obvious case is when you are trying to lock two locks, locked in a different order by different threads.
ReentrantLock lock1 = new ReentrantLock();
ReentrantLock lock2 = new ReentrantLock();
public void methodA() {
lock1.lock();
lock2.lock();
// do something and unlock both.
}
public void methodB() {
lock2.lock();
lock1.lock();
// do something and unlock both.
}
As you can see it is possible for a thread to call methodA and obtain lock1 waiting for lock2, and another thread to call methodB and obtain lock2 waiting for lock1.
However, it's possible for a thread to deadlock itself. An example is ReentrantReadWriteLock because it doesn't support upgrading a read lock to a write lock.
ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
rwl.readLock().lock();
// do we need to update?
rwl.writeLock().lock(); // will wait for the readLock() to be released!
An obscure opportunity to deadlock yourself is when implied locks are used. A static initialiser block is implicitly thread-safe so a lock is used even though static initialiser blocks are not synchronized
class A {
private static int VALUE;
static {
Thread t = new Thread() {
public void run() {
// waits for the A class to load.
VALUE = someLongTask();
}
};
t.start();
// waits for the thread.
t.join();
}
}
Again you have a deadlock!
Here's an example of deadlock with ReentrantLock
class Deadlock {
private static final ReentrantLock l1 = new ReentrantLock();
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
public void run() {
System.out.println("A Trying to lock...");
l1.lock();
System.out.println("A Locked...");
try {
Thread t = new Thread(new Runnable() {
public void run() {
System.out.println("B Trying to lock...");
l1.lock();
System.out.println("B Must not print");
try {
} finally {
System.out.println("B Trying to unlock...");
l1.unlock();
System.out.println("B Unlocked...");
}
}
});
t.start();
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
} finally {
System.out.println("A Trying to unlock...");
l1.unlock();
System.out.println("A Unlocked...");
}
}
});
t.start();
}
}
To resolve deadlock, comment out call to t.join, along with enclosing try/catch.
A reentrant lock will allow the lock holder to enter blocks of code even after it has already obtained the lock by entering other blocks of code. A non-reentrant lock would have the lock holder block on itself as it would have to release the lock it obtained from another block of code to reobtain that same lock to enter the nested lock requiring block of code.
As far as deadlock is concerned, if you call a protected block of code from a protected block of code, you'll want a reentrant lock (or you will deadlock while waiting on yourself).

Categories

Resources