How do I use wait/notifyAll
Asked Answered
P

4

6

I am wondering if it is possible in java to have a class that implements Runnable and if an object of the class goes to wait() (so thread stops running until it receives a signal), can another object of the same class notify it to continue running ?

Ideally what i want to be able to do is:

public class ThreadClass implements Runnable{

 public void run(){
 //.. Does some arbitrary work

  if( aCondition){  //have it wait until something signals it to contine exection.
 this.wait();
 }

 //Continues to do more work.

 //finished whatever it needed to do. Signal all other threads of this object type to continue their work.
 this.notifyAll();

 }
}

Is this possible and if so how would I go about doing it? I am trying to make it so that the object itself can manage itself and all other objects of the same type. So that no one using this class has to worry about managing it.

Preadamite answered 21/10, 2012 at 6:31 Comment(0)
M
6

I am trying to make it so that the object itself can manage itself and all other objects of the same type. So that no one using this class has to worry about managing it.

If you want to make every instance know about every other instance, you'd need some sort of static collection... which then makes garbage collection tricky, as well as making it all hard to test.

I would suggest you have a separate manager type whose sole job is to manage instances of this class. Then you still only need to have the logic in one place, but you don't need to know about all instances of the type - the manager just needs to know what it's managing. You may even be able to create the API so that client code only needs to see the manager, and the individual instance are hidden.

EDIT: Just to clarify, you may not even need wait/notifyAll at all - prefer the higher-level constructs in java.util.concurrent, which allow you to write producer/consumer scenarios without low-level operations such as wait. This answer addresses the higher level question of letting objects know which other objects they should be communicating with. The question's idea of all objects of one type knowing about another will lead to problems, hence the suggestion of a manager class.

Mastersinger answered 21/10, 2012 at 6:37 Comment(6)
Any help in how to make the manager? currently i only have one class creating my thread object, but not every thread will be paused- i expect about 1/10 threads will need to stop until a resource is release by another thread.Preadamite
@user597608: We'd need to know more information - we really don't know anything about what this is trying to do. If you can make your manager responsible for creating each instance, then it can pass a reference to itself to each of the instances, so they can call back when they need to signal something to the other instances managed by the same manager... does that help you?Mastersinger
I'm making a server that waits for UDP calls.It gets a message and than creates a new thread that parses the message and then enters it into an SQLite database. I'm getting the problem that the databases locks due to the fact an sqlite database is a file. I've tried a connection pool (BoneCP), but it just degraded the performance of my code by a 1/10. At the moment my server can handle 10 msg/second, but any higher than that and it craps out.Preadamite
@user597608: I don't know enough about SQLite to say for sure, but it sounds like you might be best with just one thread for SQLite access. I'd recommend not creating a new thread for each message, too - just keep a pool of them. You may well want two producer/consumer queues: a network listener puts the raw packet on one queue which may be consumed by multiple parsing threads. Each parsing thread then uses the same SQLite queue which is served by just one thread doing serial DB work.Mastersinger
I thought about that, but than i could have an issue of running out of memory. Ideally, what I want is an actual database so I wouldn't even have to worry about this :(Preadamite
@user597608: If you have an issue of running out of memory, that's an inherent problem - if you're receiving requests faster than you can process them, I don't see what you expect to do about that. Sooner or later you'll have to just stop accepting requests.Mastersinger
J
1
If( condition)
{ wait }

Ideally wait should be sorrounded by while condition instead of if block. Because client should make sure that the condition is satisfied before going ahead instead of soley relying on notify.

Junto answered 21/10, 2012 at 6:46 Comment(0)
L
1

By managing itself you might be meaning to manage synchronization on its locks and obeying the boundaries for its instance variables depending on some condition.

public class ThreadClass implements Runnable {

    public void run() {
        // .. Does some arbitrary work
        synchronized (this) {
            while (! aCondition) { // have it wait until something signals it to
                                // contine exection.
                this.wait();
            }
        }

    /*  Reset the aCondition var to its old value to allow other threads to 
        enter waiting state

        Continues to do more work.

        Finished whatever it needed to do. Signal all other threads of this
         object type to continue their work.*/
        synchronized (this) {
            this.notifyAll();
        }

    }
}

You should also take a look at the Condition interface. It seems to have the exact same requirements except that it uses the java.util.concurrent classes. There is an example of the BoundedBuffer.

See the Producer Consumer Example below. It has the same wait/notify template. The available flag is declare volatile so that thread safe reads and writes can be performed on it.

public class ProducerConsumerTest {
    public static void main(String[] args) {
        CubbyHole c = new CubbyHole();
        Producer p1 = new Producer(c, 1);
        Consumer c1 = new Consumer(c, 1);

        p1.start();
        c1.start();
    }
}



    class CubbyHole {
        private int contents;
        private volatile boolean available = false;

        public int get() {
            synchronized (this) {
                while (available == false) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
                    }
                }
            }

            available = false;
            synchronized (this) {
                notifyAll();
            }
            return contents;
        }

        public void put(int value) {
            synchronized (this) {
                while (available == true) {
                    try {
                        wait();
                    } catch (InterruptedException e) {
                    }
                }
            }
            available = true;

            contents = value;

            synchronized (this) {
                notifyAll();
            }
        }
    }

    class Consumer extends Thread {
        private CubbyHole cubbyhole;
        private int number;
        private Integer takeSum = new Integer(0);

        public Consumer(CubbyHole c, int number) {
            cubbyhole = c;
            this.number = number;
        }

        public Integer getTakeSum() {
            return takeSum;
        }

        public void run() {
            int value = 0;
            for (int i = 0; i < 100; i++) {
                value = cubbyhole.get();
                takeSum+=value;

            }

            System.out.println("Take Sum for Consumer: " + number + " is "
                    + takeSum);
        }
    }

    class Producer extends Thread {
        private CubbyHole cubbyhole;
        private int number;
        private Integer putSum = new Integer(0);

        public Integer getPutSum() {
            return putSum;
        }

        public Producer(CubbyHole c, int number) {
            cubbyhole = c;
            this.number = number;
        }

        public void run() {
            for (int i = 0; i < 100; i++) {
                int rnd = (int) (Math.random() * 10);
                cubbyhole.put(rnd);
                putSum+=rnd;
                try {
                    sleep((int) (Math.random() * 100));
                } catch (InterruptedException e) {
                }
            }
            System.out.println("Put Sum for Producer: " + number + " is " + putSum);

        }
    }
Lindahl answered 21/10, 2012 at 7:2 Comment(2)
Tried this and the only issue I'm having with it is that the threads aren't being woken up no the notify call.Preadamite
The CubbyHole Producer-Consumer example is a good way to understand the wait/notify mechanism. I have done it in the same template as above.Lindahl
C
1

You asked

can another object of the same class notify it to continue running ?

Absolutely yes! - if objects are blocked waiting on this object calling notifyAll from any instance of any class will allow them to run. (including the the Runnable waiting on itself)

notifyAll doesnt care about the type of a class that it notifies, it notifies ANY class that is waiting on this object. (using it as a lock).

And for that matter any instance of any class can call either wait or notify on any object. wait and notify are public methods on java.lang.Object

See this tutorial on wait, notify.

http://www.java-samples.com/showtutorial.php?tutorialid=306

Cramoisy answered 21/10, 2012 at 7:10 Comment(1)
The OP hasn't "posed the question incorrectly" - he's posted code which doesn't do what he wants it to, but that's not the same thing.Mastersinger

© 2022 - 2024 — McMap. All rights reserved.