Синхронизированные потоки в 1 классе

Я искал способ успешно использовать несколько потоков и синхронизацию. Я пробовал использовать wait() и notify(), но мои потоки по-прежнему не синхронизируются. У меня есть более крупный проект, но в двух словах мне нужно, чтобы он запускал поток с методом установки (thread1 в этом случае) заданное количество раз, и после каждого «набора» мне нужен поток с методом получения (thread2) запустить и получить объект. Я просмотрел много других примеров, но я не могу понять это, поэтому любая помощь или объяснение того, почему это не работает, будут оценены.

Иногда это работает, когда поток 1 запускается первым, но в других случаях поток 2 запускается первым, поэтому синхронизация не работает.

Спасибо.

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();
    }
}

person Carol    schedule 09.03.2013    source источник
comment
Какова цель метода getList()? Вы не используете его.   -  person bsiamionau    schedule 10.03.2013
comment
Не изобретайте велосипед. Используйте BlockingQueue   -  person Boris the Spider    schedule 10.03.2013
comment
@bmorris591 Но что, если я хочу квадратное колесо ;)   -  person Peter Lawrey    schedule 10.03.2013
comment
это кажется таким далеким от всего, что может быть полезным или даже поучительным. и ТАК получает много этого. это школьное задание? кто будет назначать этот вид барахла?   -  person Nathan Hughes    schedule 10.03.2013
comment
@NathanHughes К сожалению, плохие примеры могут быть популярными и копироваться снова и снова, что очень затрудняет их уничтожение. vanillajava.blogspot.com.au/ 2012/08/   -  person Peter Lawrey    schedule 10.03.2013
comment
Мой вопрос в основном о том, как заставить один поток обновлять список объектов несколько раз, а другой поток извлекать состояние этих объектов каждый раз, когда они изменяются. Я смотрел на BlockingQueue, как предложил @bmorris591, но я не знаю, какой была бы лучшая альтернатива. Мое задание заключается не в добавлении строк в список, я привел это в качестве примера.   -  person Carol    schedule 10.03.2013


Ответы (3)


Используйте BlockingQueue для автоматической синхронизации, используйте ExecutorService для обработки всех Thread

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
    }
}

Убедитесь, что вы shutdown() ExecutorService когда закончите, иначе ваша программа не выйдет.

person Boris the Spider    schedule 09.03.2013

Когда вы уведомляете, вы должны обновить состояние (как у вас есть), которое должно проверяться в цикле, когда вы ждете. Это требуется как

  • триггер уведомления перед началом ожидания и потерей сигнала
  • ожидание может проснуться ложно.

Примечание: ваш потребляющий поток не ждет, потому что вы не вызываете ничего, что ждет.

Есть несколько способов исправить это, но ИМХО лучшее решение — использовать BlockingQueue, который был разработан для поддержки этого шаблона.

person Peter Lawrey    schedule 09.03.2013

Вы не должны использовать геттер и сеттер для доступа ко всему списку, а только для добавления и извлечения элементов из него. Как уже было сказано, BlockingQueue — это реализация синхронизированного списка.

Другими словами, если вы хотите реализовать это самостоятельно, замените getList на синхронизированный remove(0) в списке, который возвращает только первый элемент ArrayList.

person didierc    schedule 09.03.2013