Carol
Carol

Reputation: 3

Synchronized Threads in 1 Class

I have been searching for a way to use multiple threads and synchronization successfully. I've tried using wait() and notify(), but my threads still don't synchronize. I have a bigger project, but in a nutshell, I need it to run a thread with a setter method (thread1 in this case) a predetermined number of times and after each "set" I need the thread with the getter method (thread2) to run and get the object. I have looked at many other examples, but I can't seem to work it out, so any help or explanation of why this isn't working would be appreciated.

This works sometimes, when thread1 runs first, but some other times thread2 runs first, so the synchronization isn't working.

Thanks.

import java.util.ArrayList;

public class ThreadTest{

    private ArrayList<Object> myList;

    public ThreadTest(){

        myList = new ArrayList<Object>();

        Thread thread1 = new Thread(){
            public void run(){
                for(int i = 0; i < 10; i++){
                    addToList("" + i);
                }
            }
        };

        Thread thread2 = new Thread(){
            public void run(){
                for(int i = 0; i < 10; i++){
                    System.out.print(myList.get(i) + " ");
                }
            }
        };

        thread1.start();
        thread2.start();
    }

    public synchronized void addToList(String a){
        myList.add(a);
        notify();
    }

    public synchronized ArrayList<Object> getList(){
        try{
            wait();
        }
        catch (InterruptedException e){
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return myList;
    }

    public static void main(String[] args){
        new ThreadTest();
    }
}

Upvotes: 0

Views: 98

Answers (3)

Boris the Spider
Boris the Spider

Reputation: 61168

Use a BlockingQueue to do your syncronization automagically, use an ExecutorService to deal with all the Threads

public void doStuff() {
    final Object finishSupplying = new Object();
    final BlockingQueue<Object> myList = new LinkedBlockingQueue<Object>();
    final Runnable supplier = new Runnable() {
        public void run() {
            for (int i = 0; i < 10; i++) {
                myList.add(i);
            }
        }
    };

    final Runnable consumer = new Runnable() {
        public void run() {
            while (true) {
                try {
                    final Object thing = myList.take();
                    if(thing == finishSupplying) break;
                    System.out.print(thing + " ");
                } catch (InterruptedException ex) {
                    Thread.currentThread().interrupt();
                }
            }
        }
    };

    final ExecutorService exectutorService = Executors.newFixedThreadPool(2);
    final Future<?> supplierHandle = exectutorService.submit(supplier);
    final Future<?> consumerHandle = exectutorService.submit(consumer);
    try {
        supplierHandle.get();
    } catch (InterruptedException ex) {
        Thread.currentThread().interrupt();
    } catch (ExecutionException ex) {
        //PROBLEMS, handle
    }
    myList.add(finishSupplying);
    try {
        consumerHandle.get();
    } catch (InterruptedException ex) {
        Thread.currentThread().interrupt();
    } catch (ExecutionException ex) {
        //PROBLEMS, handle
    }
}

Make sure you shutdown() the ExecutorService when you're done otherwise you're program will not exit.

Upvotes: 2

didierc
didierc

Reputation: 14750

You should not use getter & setter to access the whole list, but only to push and pull elements from it. As it has been said, BlockingQueue is a synchronized list implementation.

In other words, if you want to implement this by yourself, replace getList with a synchronized remove(0) on the list, which only returns the first element of the ArrayList.

Upvotes: 0

Peter Lawrey
Peter Lawrey

Reputation: 533710

When you notify, you should update a state (as you have) which must be checked in a loop when you wait. This is required as

  • the notify trigger before wait starts and the signal is lost
  • the wait can wake spuriously.

Note: your consuming thread doesn't wait because you are not calling anything which waits.

There is a number of ways to fix this but IMHO the best solution is to use a BlockingQueue which was designed to support this pattern.

Upvotes: 1

Related Questions