How to correctly use signaling via shared objects? - java

I'm currently studying about signaling in threads and came across this article for signaling via shared objects,
http://tutorials.jenkov.com/java-concurrency/thread-signaling.html
It says that we can create a shared object and pass that object to threads which, threads can use to signal each other.
Following is the snippet provided for shared object,
public class MySignal{
protected boolean hasDataToProcess = false;
public synchronized boolean hasDataToProcess(){
return this.hasDataToProcess;
}
public synchronized void setHasDataToProcess(boolean hasData){
this.hasDataToProcess = hasData;
}
}
I tried to use it in my class as,
class MySignal {
boolean hasDataToProcess = false;
public MySignal(boolean defaultValue) {
this.hasDataToProcess = defaultValue;
}
public synchronized boolean hasDataToProcess() {
return this.hasDataToProcess;
}
public synchronized void setHasDataToProcess(boolean hasDataToProcess) {
this.hasDataToProcess = hasDataToProcess;
}
}
class MyThreadRunnable implements Runnable {
MySignal sharedSignal;
MyThreadRunnable(MySignal signal) {
this.sharedSignal = signal;
}
#Override
public void run() {
System.out.println(Thread.currentThread().getName() + " starts running..");
synchronized (sharedSignal) {
System.out.println(Thread.currentThread().getName() + " accessing sharedSignal");
while(sharedSignal.hasDataToProcess()) {
sharedSignal.setHasDataToProcess(false);
try {
System.out.println(Thread.currentThread().getName() + " going to sleep");
Thread.sleep(3000);
} catch (InterruptedException e) {
}
}
sharedSignal.setHasDataToProcess(true);
System.out.println(Thread.currentThread().getName() + " ended.");
}
}
}
public class Test2 {
public static void main(String[] args) {
MySignal mySignal = new MySignal(true);
MyThreadRunnable t1 = new MyThreadRunnable(mySignal);
MyThreadRunnable t2 = new MyThreadRunnable(mySignal);
Thread t3 = new Thread(t1);
Thread t4 = new Thread(t2);
t3.start();
t4.start();
}
}
This provided the expected output as,
Thread-1 starts running..
Thread-0 starts running..
Thread-1 accessing sharedSignal
Thread-1 going to sleep
Thread-1 ended.
Thread-0 accessing sharedSignal
Thread-0 going to sleep
Thread-0 ended.
But even if I remove the synchronized on the MySignal methods, this provides the same output as sharedSignal object is locked by one of the threads.
And, if I remove only the synchronized in run(), it does not work properly as one of the threads end before even going to sleep.
So this code is only running correctly due to the lock on sharedSignal object.
Is this how the signaling has to be used?
My intuition says that I've missed something. I tried searching for a good example but no luck so far. Any help would be appreciated.

But even if I remove the synchronized on the MySignal methods, this
provides the same output as sharedSignal object is locked by one of
the threads
Removing the synchronized from the methods won't make a difference as there is already a synchronized block guarding the method access from different threads.
And, if I remove only the synchronized in run(), it does not work
properly as one of the threads end before even going to sleep.
But if you remove the the synchronized block then the contents of the block are not executed in an atomic way.
What I mean is without the synchronized block the any thread can call the sharedSignal.hasDataToProcess() get the lock on the MySignal object and then release it after it is done with the method then another thread is free to call the sharedSignal.setHasDataToProcess(false); as the lock on the MySignal instance was already released by the earlier thread when it was done with the method.
//Acquires lock for the entire block
synchronized (sharedSignal) {
System.out.println(Thread.currentThread().getName() + " accessing sharedSignal");
while(sharedSignal.hasDataToProcess()) {
sharedSignal.setHasDataToProcess(false);
try {
System.out.println(Thread.currentThread().getName() + " going to sleep");
Thread.sleep(3000);
} catch (InterruptedException e) {
}
}
sharedSignal.setHasDataToProcess(true);
System.out.println(Thread.currentThread().getName() + " ended.");
}
Now without the synchronized block, the code of the block is not executed in an atomic way:
System.out.println(Thread.currentThread().getName() + " accessing sharedSignal");
//say thread1 acquires lock here
while(sharedSignal.hasDataToProcess()) {
//thread1 releases lock here, thread2 can acquire lock on the same object
sharedSignal.setHasDataToProcess(false);
try {
System.out.println(Thread.currentThread().getName() + " going to sleep");
Thread.sleep(3000);
} catch (InterruptedException e) {
}
}
sharedSignal.setHasDataToProcess(true);
System.out.println(Thread.currentThread().getName() + " ended.");
}

Related

Java Thread is blocked in join()

I have the following simple code in which I put and take from a Queue represented as an ArrayList.
public class EmailService {
private Queue<Email> emailQueue;
private Object lock;
private volatile boolean run;
private Thread thread;
public void sendNotificationEmail(Email email) throws InterruptedException {
emailQueue.add(email);
synchronized (lock) {
lock.notify();
lock.wait();
}
}
public EmailService() {
lock = new Object();
emailQueue = new Queue<>();
run = true;
thread = new Thread(new Runnable() {
#Override
public void run() {
while (run) {
System.out.println("ruuuning");
synchronized (lock) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
if (emailQueue.getSize() > 0) {
sendEmail(emailQueue.poll());
}
lock.notify();
}
}
}
private void sendEmail(Email email) {
System.out.println("Sent email from " + email.getFrom() + " to " + email.getTo() + " with content: " + email.getContent());
}
});
thread.start();
}
public void close() throws InterruptedException {
run = false;
synchronized (lock) {
lock.notify();
System.out.println("Thread will join " + thread.isInterrupted());
thread.join();
System.out.println("Thread after join");
}
}
}
I don't understand why my thread is blocked in join() method.
From main I call as follow:
eService = new EmailService();
Email e1 = new Email(client1, client2, "content1");
eService.sendNotificationEmail(e1);
eService.close();
Without running it...
The close() method holds lock at the time it calls thread.join() and waits on thread (forever)
thread is waiting to reacquire lock so cannot run
Both are now waiting on each other, this is a deadlock. Try moving the Thread.join() after the synchronized block:
public void close() throws InterruptedException {
run = false;
synchronized (lock) {
lock.notify();
System.out.println("Thread will join " + thread.isInterrupted());
}
thread.join();
System.out.println("Thread after join");
}
#drekbour explained how your program could hang in the join() call, but FYI: Here's a different way that your program could hang. This is called lost notification.
Your main thread creates a new EmailService instance. The new instance creates its thread and calls thread.start() *BUT* it could take some time for the thread to actually start running. Meanwhile...
Your main thread creates a new Email instance, and calls eService.sendNotificationEmail(...). That function adds the new message to the queue, locks the lock, notifies the lock, and then waits on the lock.
Finally, The service thread starts up, enters its run() method, locks the lock, and then it calls lock.wait().
At this point, the program will be stuck because each thread is waiting to be notified by the other.
The way to avoid lost notification is, in the consumer thread, do not call wait() if the thing that you are waiting for already has happened.
synchronized(lock) {
while (theThingHasNotHappenedYet()) {
lock.wait();
}
dealWithTheThing();
}
In the producer thread:
synchronized(lock) {
makeTheThingHappen();
lock.notify();
}
Notice how both threads lock the lock. Ever wonder why lock.wait() throws an exception if the lock isn't locked? The examples above illustrate why. The lock prevents the producer thread from making the thing happen after the consumer already has decided to wait. That is key: If the consumer were to wait after the producer calls notify() then it's game over. The program hangs.

How do I ensure that a thread is started before another thread?

I have 2 threads T1 and T2. T2 should start its work after it gets a message from T1. Both T1 and T2 are started in main(). T1 can't start T2.
This is what I have so far:
T1:
//do work1 which should be executed before work2
lock2.notify()
T2:
lock2.wait();
//do work2 which should be executed after work1 ends
The problem is that sometimes T1 is started before T2 and T2 never gets the notify sent by T1 and waits forever.
Can I use any existing concurrency utilities to achieve this signalling?
Thanks.
You need some synchronisation mechanism between the two threads. Below is an example where I use a CountDownLatch for that purpose. I defined a class SyncedThread which gets a CountDownLatch passed in the constructor.
In the main method I then create two instances of this class. The first, thread1 will run for 2 seconds, then signal the CountDownLatch and then do some dummy sleep for another 3 seconds.
The second instance thread2 will wait for the CountDownLatch and will then sleep 5 seconds simulating work.
thread2.start() method is called first, then the thread1.start() with a delay of 500ms, but by using the synchronisatio you will see in the output that actually thread2 is waiting for thread1.
public class ThreadStarterTest {
public static void main(String[] args) {
final CountDownLatch latch = new CountDownLatch(1);
SyncedThread thread1 = new SyncedThread(latch, "thread 1") {
#Override
public void run() {
try {
System.out.println(getName() + " running");
Thread.sleep(2_000);
latch.countDown();
Thread.sleep(3_000);
System.out.println(getName() + " finished");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
SyncedThread thread2 = new SyncedThread(latch, "thread 2") {
#Override
public void run() {
try {
latch.await();
System.out.println(getName() + " running");
Thread.sleep(5_000);
System.out.println(getName() + " finished");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
try {
thread2.start();
Thread.sleep(500);
thread1.start();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static class SyncedThread extends Thread {
private final CountDownLatch latch;
public SyncedThread(final CountDownLatch latch, final String name) {
super(name);
this.latch = latch;
}
}
}
In general, whenever you use wait() and notify(), you should also have some sort of mechanism (such as a marker variable) to check to see if you're done waiting. From the Javadoc for wait():
[…] this method should always be used in a loop:
synchronized (obj) {
while (<condition does not hold>)
obj.wait();
... // Perform action appropriate to condition
}
In your case that means that you simply never enter the loop if you don't actually need to wait.
That said, you might want to reconsider launching both threads from main(); from your description, it's not obvious why you're doing it that way.
You should make T1 waits while t2 has not sent the message.
Add a shared variable to represent the message and use it in a while statement.
And after lock2.send(); invokelock2.notify();` in T2 in order to notify T1 if it waits for.
T1:
while (lock2.isNotSend()){
lock2.wait();
}
lock2.notify()
//do some work
T2:
// processing that sends the message
lock2.send();
lock2.notify();
lock2.wait();

notifyAll() does not work

In the following code the notifyAll() is called but does not reactivate the other threads. The output I get is
beta waiting to get notified at time: 1441870698303, activeWriters: 1
alpha waiting to get notified at time: 1441870698303, activeWriters: 1
delta notify all at time: 1441870698403, activeWriters: 0
public class Waiter implements Runnable{
private static int activeWriters;
public Waiter(Message msg){
}
#Override
public void run() {
beforeWrite();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
afterWrite();
}
protected synchronized void beforeWrite(){
while (activeWriters > 0 ) {
try {
System.out.println(Thread.currentThread().getName() +" waiting to get notified at time: "+System.currentTimeMillis()+ ", activeWriters: " + activeWriters);
wait();
System.out.println(Thread.currentThread().getName() +" waiting got notified at time: "+System.currentTimeMillis()+ ", activeWriters: " + activeWriters);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
++activeWriters;
}
protected synchronized void afterWrite(){
--activeWriters;
System.out.println(Thread.currentThread().getName() +" notify all at time: "+System.currentTimeMillis() + ", activeWriters: " + activeWriters);
notifyAll();
}
}
public class WaitNotifyTest {
public static void main(String[] args) {
Message msg = new Message("process it");
Waiter waiter1 = new Waiter(msg);
Waiter waiter2 = new Waiter(msg);
Waiter waiter3 = new Waiter(msg);
new Thread(waiter1,"alpha").start();
new Thread(waiter2, "beta").start();
new Thread(waiter3, "delta").start();
}
}
The calls wait() and notify*() work on a specified object, meaning that notify*() wakes up threads which called wait() on the same object.
In your case you call wait() and notifyAll() on 3 different objects which aren't connected, so this can't work.
You can add a static mutex:
private static final Object mutex = new Object();
and then call wait() and notify*() on this object. Remeber to synchronize on the mutex first:
synchronized (mutex) {
...
mutex.wait();
...
}
and:
synchronized (mutex) {
...
mutex.notifyAll();
...
}
All access to activeWriters must be in these synchronized blocks for 2 reasons. Currently access to it is effectively unsynchronized, because you synchronize on 3 different objects. Apart from that activeWriters is your condition variable, and you want to notify*() other threads that it changed. For this to work the change of the variable and the notify*() call must be in the same synchronized block.
There is a major design flaw in your program.
You are creating 3 separate instances of Waiter class and expect all them to access activeWriters in synchronized fashion. This is not possible because instance methods will acquire different locks but modify same static variable activeWriters.
To provide static variables concurrent access, you should access them via. synchronized static methods.
One way could be to make beforeWrite() and afterWrite() methods static.

Reason for IllegalMonitorStateException

I am getting an Illegal State exception for following code :
synchronized (this) {
try {
Thread.currentThread().wait();
notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
What i could made is synchronized on "this" will capture Monitor on Object calling the method and since i am calling wait on Current Thread object and i really don't have lock on that i am getting t error. Please validate my theory.
You call wait on the current thread, call it on this.
this.wait();
but then you will never get a notifyAll , because no thread that enters the synchronized block
can ever reach the notofyAll method. They all will wait for it first.
I guess you want one Thread to wait for another Thread to do some work.
Here is a short example of how synchronization between threads can work
public class ThreadTest {
public static void main(String[] args) throws InterruptedException {
Object monitor = new Object();
Thread t1 = new Thread(new R1(monitor));
Thread t2 = new Thread(new R2(monitor));
t1.start();
t2.start();
t2.join();
t1.join();
}
public static class R1 implements Runnable {
private Object monitor;
public R1(Object monitor) {
this.monitor = monitor;
}
public void run() {
System.out.println("R1 entered run");
synchronized (monitor) {
try {
monitor.wait();
System.out.println("R1 got monitor back");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static class R2 implements Runnable {
private Object monitor;
public R2(Object monitor) {
this.monitor = monitor;
}
public void run() {
System.out.println("R2 entered run");
synchronized (monitor) {
System.out.println("R2 will sleep for 1 sec");
try {
Thread.sleep(1000);
System.out
.println("R2 will notify all threads waiting for monitor");
monitor.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
Output is:
R1 entered run
R2 entered run
R2 will sleep for 1 sec
R2 will notify all threads waiting for monitor
R1 got monitor back
You have acquired the lock of
this(current object)
and you are calling `
wait()
` on current thread that is why.
you should acquire lock before calling wait, notify notifyAll
Case1
...
synchronized(this){
this.wait();
}
...
Case2
...
synchronized(this){
Thread.currentThread.wait();
}
...
Case 1 is sensible code. It waits until another thread calls notify[All]() on "this" object.
Case 2 looks silly. It could only execute if the current thread and "this" were the same object, or you already had a lock on the current thread. Otherwise, you'd get IllegalMonitorStateException. Synchronising on Thread objects is a Bad Thing, because you can't be sure what else might be synchronising on them.
By the way, if what you want to do is just pause for a while in the program, you should sleep(), not wait().
From the Java doc for Object class wait() method:
IllegalMonitorStateException - if the current thread is not the owner
of the object's monitor.
In your code, current thread is the owner of the monitor of this and wait is called on Thread.currentThread.
Replace Thread.currentThread().wait(); with this.wait();

About wait and notifyAll

I've this class:
public class MyThread implements Runnable {
private static boolean canAccess = true;
private Thread t;
public FirstThread(String name) {
t = new Thread(this);
t.setName(name);
}
public void start() {
t.start();
}
private synchronized void accessed(String name) throws InterruptedException {
if (canAccess) {
canAccess = false;
System.out.println("Accessed " + name);
try {
Thread.sleep(5000);
} catch (Exception e) {
}
canAccess = true;
System.out.println("NOTIFY: " + name);
notifyAll();
}
System.out.println("WAIT: " + name);
wait();
}
#Override
public void run() {
while (true) {
try {
accessed(Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
And this is my output:
Accessed 1
WAIT: 3
WAIT: 5
WAIT: 7
WAIT: 9
WAIT: 0
WAIT: 2
WAIT: 4
WAIT: 6
WAIT: 8
NOTIFY: 1
WAIT: 1
and my app freeze (deadlock state).
Seems that the notifyAll method doesn't work. Where is my error?
My Main class.
public class Main {
public static void main(String[] args) {
MyThread [] threads = new MyThread[10];
for(int i=0;i<threads.length;i++) {
threads[i] = new MyThread(""+i);
threads[i].start();
}
}
}
wait means that the thread releases the lock and goes into a dormant state until another thread notifies it. notifyAll means that the thread tells all the other threads waiting on the lock being used in the current synchronized block to wake up and try to acquire the lock again. Your code example doesn't have any cases where multiple threads are trying to acquire the same lock so using wait and notifyAll here doesn't make any sense. There's nothing to wake up the thread once it calls wait.
One typical use of wait and notify: You might have many producers putting stuff in a queue, and consumer threads that take stuff out of the queue. The queue has a take method that the consumer calls, if the queue is empty then it calls wait and the consumer blocks. The queue has a put method that calls notifyAll when something goes into the queue so that any waiting consumer threads wake up.
There's a producer-consumer example of using wait and notifyAll in the Java tutorial.
Every Thread waits on it's own instance, that's why they all are stuck in one place.
If you had a private static Object LOCK = new Object(); and call LOCK.wait(); and LOCK.notify(); this could be another story.
I have also doubts about synchronized modifier for accessed() method. It's just doesn't have use in the described situation. I would better modify the "canAccess" variable in synchronized block.

Categories

Resources