stuck with wait() and notify()

Hi,

I have a problem understanding synchronous access.

I have an object that should provide a list of data. The list is used later in my code, but it would increase performance to load it in a separate thread at the beginning. However it is possible that the list is not ready when the first other object tries to access the list.

I thought that this code should solve the problem

publicclass SingleObjectimplements Runnable{

ArrayList list;

public SingleObject(){

list =new ArrayList();

}

publicsynchronizedvoid run(){

try{

makeALongProc(100);

}catch (InterruptedException e){

e.printStackTrace();

}

notify();

}

privatesynchronizedvoid makeALongProc(int size)throws InterruptedException{

System.out.println("...doing something ...");

Thread.sleep(5000);

for (int i = 0 ; i < size ; i++ ){

list.add(""+i);

}

System.out.println("finished!");

notifyAll();

}

publicsynchronized String getValueAt(int pos)throws InterruptedException{

wait();

return list.get(pos).toString();

}

publicsynchronized List getList()throws InterruptedException{

wait();

return list;

}

}

The object is invoked by the following code.

publicclass ThreadProject{

/**

* @param args

*/

publicstaticvoid main(String[] args){

System.out.println("...starting thread...");

SingleObject so =new SingleObject();

Thread th =new Thread(so);

th.start();

try{

System.out.println("waiting ...");

List list = so.getList();

System.out.println("got list"+list.size());

String sso = so.getValueAt(5);

System.out.println(sso);

}catch (InterruptedException e){

e.printStackTrace();

}

}

}

Unfortunateley this is not doing what I have expected. Instead of calling the methodsso.getList() andso.getValueAt() it enters so.getList() and waits and waits....

Can anybody give my a clue or an explanation what I am doing wrong?

Regards

Sas

Message was edited by:

Poncho1975

[4251 byte] By [Poncho1975a] at [2007-10-3 10:08:07]
# 1
Sounds like a job for [url http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/ArrayBlockingQueue.html]java.util.concurrent.ArrayBlockingQueue[/url].
Caffeine0001a at 2007-7-15 5:27:45 > top of Java-index,Core,Core APIs...
# 2

Your code doesn't make sense.

You start a thread that sleeps 5 seconds and then creates 100 items in an array and then notifies itself. (notifyAll() doesn't specify the object to notify.) And then it notifies itself again.

Your call to so.getList() issues a wait() but there is no notify to release it.

You need to understand the relationship to wait()/notify(). There are numberous examples all over this forum. Try a search on producer/consumer. See the java.util.concurrent.Locks Condition interface for an example of await()/signal() which is like wait/notify.

cooper6a at 2007-7-15 5:27:45 > top of Java-index,Core,Core APIs...
# 3

I have tried a little bit further.

I changed the following part:

public class SingleObject {

ArrayList list;

public SingleObject(){

list = new ArrayList();

}

public synchronized void makeALongProc(int size) throws InterruptedException{

System.out.println("...doing something ...");

Thread.sleep(5000);

for (int i = 0 ; i < size ; i++ ){

list.add(""+i);

}

System.out.println("finished!");

notify();

}

public synchronized String getValueAt(int pos) throws InterruptedException{

if (list==null || list.size()<=pos){

wait();

}

return list.get(pos).toString();

}

public synchronized List getList() throws InterruptedException{

if (list==null){

wait();

}

return list;

}

}

and ...

public class ThreadProject {

/**

* @param args

*/

public static void main(String[] args) {

System.out.println("...starting thread...");

final SingleObject so = new SingleObject();

Thread th = new Thread(new Runnable(){

public synchronized void run() {

try {

so.makeALongProc(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

});

th.start();

try {

System.out.println("waiting ...");

List list = so.getList();

System.out.println("got list"+list.size());

String sso = so.getValueAt(5);

System.out.println(sso);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

Now I am satisfied. Every call on a method from this object would lead to the situation, that either makeALongProc is called first or all other methods must wait until makeALongProc has been called once to fill the array.

However I suppose that accessing elements of a list with a synchronized object is not a good decision. I would rather take only the whole List and do all other access outside of the object.

Regards

Poncho

Poncho1975a at 2007-7-15 5:27:45 > top of Java-index,Core,Core APIs...
# 4
Your use of wait/notify is incorrect. Please search for the correct way to use wait() in a loop.Also your Thread run() method need not be synchronized.
davidholmesa at 2007-7-15 5:27:45 > top of Java-index,Core,Core APIs...
# 5

There is so many ways this could be down with the classes in java.util.concurrent. As I suggest above one way is with

java.util.concurrent.ArrayBlockingQueue.

public class SingleObject {

List<String> currentList;

BlockingQueue<List><String>> queueOfLists = new ArrayBlockingQueue<List><String>>(1);

public void makeALongProc(int size) throws InterruptedException {

System.out.println("...doing something ...");

Thread.sleep(5000);

ArrayList<String> list = new ArrayList<String>();

for (int i = 0 ; i < size ; i++ ){

list.add(""+i);

}

queueOfLists.put(list);

System.out.println("finished!");

}

public List<String> getList() throws InterruptedException {

List<String> list = queueOfLists.poll();

if (list == null && currentList == null) { //no new list and no currentList

list = queueOfLists.take();

}

if (list != null) {// have a new list

currentList = list;

}

return currentList;

}

}

As you can see no synchronized keyword and your list isn't synchronized, and as long as you don't write to it you can access it concurrent after calling getList().

Caffeine0001a at 2007-7-15 5:27:45 > top of Java-index,Core,Core APIs...
# 6
A SynchronousQueue() probable could have been used instead of the ArrayBlockingQueue(1).
Caffeine0001a at 2007-7-15 5:27:45 > top of Java-index,Core,Core APIs...
# 7

If you are only working with one list at a time and need to modify one while working on the other you could use [url http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/Exchanger.html]Exchanger[/url] classes to exchange to the Lists. One or more thread would use one list while the other thread modifies the other. Then you could exchange the two lists and continue processing.

Caffeine0001a at 2007-7-15 5:27:45 > top of Java-index,Core,Core APIs...
# 8

Want you want could also be implemented using [url http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/CyclicBarrier.html]CyclicBarrier[/url]. See the example from that link. You could even use the [url http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/Executors.html]Executors[/url] class to schedule the population of the List and use Future objects to return the list. As I said there are plenty of ways to do want you want in the [url http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/package-summary.html]java.util.concurrent[/url] package. It makes doing a lot of what wait() and notify() used to do a lot easier and less bug prone.

Caffeine0001a at 2007-7-15 5:27:45 > top of Java-index,Core,Core APIs...
# 9

Thanks all. I have been continuing searching for a better solution.

However classes from 1.4 to 6 are no option as I need to use

a 1.3.1 Version.

@ davidholmes: I understand your willingness to help, but you answer is of no value. No offense, but it would be as if you're sick and you go to the doctor. And he would tell you that you're sick but gives you no clue what you have or how you can cure it.

Message was edited by:

Poncho1975

Message was edited by:

Poncho1975

Poncho1975a at 2007-7-15 5:27:45 > top of Java-index,Core,Core APIs...
# 10

I think I understood now what was wrong.

The usage of notify() and wait() is not needed here.

Reason why I though so was that creating the thread takes so long, that the original thread is calling the method of getting the list before it is filled.

synchronizing is absolutely enough in in my case.

Regards

Poncho

Poncho1975a at 2007-7-15 5:27:45 > top of Java-index,Core,Core APIs...
# 11

> @ davidholmes: I understand your willingness to help,

> but you answer is of no value. No offense, but it

> would be as if you're sick and you go to the doctor.

> And he would tell you that you're sick but gives you

> no clue what you have or how you can cure it.

No it's like being told by a teacher that you don't understand something you are doing and should go and learn how to use it - in this case how to use wait/notify.

Sorry if my response was a little short but repeating how to correctly use wait/notify many times in different posts is rather tedious - hence I told you to search. One day I'll put together a FAQ and when that happens I'll direct people to the FAQ.

davidholmesa at 2007-7-15 5:27:45 > top of Java-index,Core,Core APIs...
# 12
There are back-ports available. One such is http://dcl.mathcs.emory.edu/util/backport-util-concurrent/
Caffeine0001a at 2007-7-15 5:27:45 > top of Java-index,Core,Core APIs...