Модераторы: LSD, AntonSaburov
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> многопоточная задача про философов 
V
    Опции темы
Pawl
Дата 27.3.2013, 12:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 649
Регистрация: 22.4.2008
Где: Витебск

Репутация: 7
Всего: 28



Доброго времени суток, возможно, все слышали про сабж - это там, где философы сидят в кружок за столом, покушают спагетти, потом подумают, потом опять покушают и т. д., пока спагетти не кончатся. Проблема состоит в том, что спагетти надо есть 2-мя вилками, а количество вилок на столе совпадает с количеством философов. Поэтому некоторые философы, для того чтобы поесть, должны ждать освобождения вилок. Обычно эту задачу приводят, как демонстрацию синхронизации и дедлоков. Я сперва ее реализовал с использованием synchronized и volatile там, где посчитал нужным, а потом для интереса их убрал. Так вот, это нисколько не повлияло на работу программы! Т. е. никакой одновременности в поедании спагетти сразу всеми философами не случилось, хотя, на сколько я понимаю, она должна быть. Вот исходный код классов программы:
Вилка - 
Код

public class Fork {
    private boolean free = true;

    public boolean isFree() {
        return free;
    }

    public void setFree(boolean free) {
        this.free = free;
    }
}

тарелка - 
Код

public class Plate {
    private int spaghetti;

    public Plate(int spaghetti) {
        this.spaghetti = spaghetti;
    }

    public void getSpaghetti() {
        spaghetti--;
    }

    public boolean isEmpty() {
        return spaghetti == 0;
    }
}

философ - 
Код

public class Philosopher implements Runnable {
    // левая и правая вилки
    private Fork f1, f2;
    // тарелка со спагетти
    private Plate plate;
    private String name;

    public Philosopher(String name, Plate plate, Fork f1, Fork f2) {
        this.f1 = f1;
        this.f2 = f2;
        this.plate = plate;
        this.name = name;
    }
    // философ ест
    private void eat() {
        // берет вилки
        f1.setFree(false);
        f2.setFree(false);
        // ест спагетти
        for (int i = 0; i < 5; i++) {
            if (plate.isEmpty()) {
                break;
            }
            System.out.printf("%-10s %s %n", name, " eat");
            plate.getSpaghetti();
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
            }
        }
        // кладет вилки на стол
        f1.setFree(true);
        f2.setFree(true);
    }

    // процесс питания
    @Override
    public void run() {
        // пока тарелка не пуста
        while (!plate.isEmpty()) {
            // если вилки свободны, съесть немного спагетти
            if (f1.isFree() && f2.isFree()) {
                eat();
            }
            // подумать
            think();
        }
        // встать из-за стола
        System.out.printf("%-10s %s %n", name, " DONE ");
    }

    // философ думает над непустой тарелкой
    public void think() {
        if (plate.isEmpty()) {
            return;
        }
        System.out.printf("%-10s %s %n", name, " think");
        try {
            Thread.sleep(2);
        } catch (InterruptedException e) {
        }
    }

    // запуск процесса
    public void start() {
        new Thread(this).start();
    }
}

стол - 
Код

public class Table {
    // накрываем стол, рассаживаем по кругу философов и вперед
    public static void main(String[] args) {
        int spaghetti = 50;
        Fork f1 = new Fork();
        Fork f2 = new Fork();
        Fork f3 = new Fork();
        Fork f4 = new Fork();
        Plate p1 = new Plate(spaghetti);
        Plate p2 = new Plate(spaghetti);
        Plate p3 = new Plate(spaghetti);
        Plate p4 = new Plate(spaghetti);
        new Philosopher("Socrat", p1, f1, f2).start();
        new Philosopher("Platon", p2, f2, f3).start();
        new Philosopher("Camu",   p3, f3, f4).start();
        new Philosopher("Kant",   p4, f4, f1).start();
    }
}

Я считаю, что в методе eat класса Philosopher два философа, впринципе, могут одновременно захватить одну и ту же вилку, т. к. доступ к вилкам не синхронизирован. Кроме того, значение переменной free у вилки, по идее, кэшируется потоками, т. е. другой поток может не сразу узнать ее текущее значение. Изначально я объявил метод eat как synchronized, а переменную free - как volatile. Потом убрал эти объявления, результат работы остался тем же. Буду благодарен, если объясните почему. Спасибо! 


--------------------
В действительности всё совсем не так, как на самом деле
PM MAIL   Вверх
Pawl
Дата 27.3.2013, 14:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 649
Регистрация: 22.4.2008
Где: Витебск

Репутация: 7
Всего: 28



На 'дцатом запуске мои подозрения подтвердились! smile Тема закрыта.
Блин, хотел на примере этого продемонстрировать принципы синхронизации, но как можно, если разница возникает только после многочисленных запусков smile 

Это сообщение отредактировал(а) Pawl - 27.3.2013, 14:40


--------------------
В действительности всё совсем не так, как на самом деле
PM MAIL   Вверх
batigoal
Дата 27.3.2013, 15:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Нелетучий Мыш
****


Профиль
Группа: Участник Клуба
Сообщений: 6423
Регистрация: 28.12.2004
Где: Санктъ-Петербургъ

Репутация: 24
Всего: 151



Pawl, если бы она проявлялась каждый раз, то проблемы многопоточности не были бы такими геморройными =)

Я не смотрел текст, но обычно можно повысить вероятность до почти 100% за счет sleep-ов в выполняемых потоках и паузах между их запуском (например, секунда задержки в цикле-worker'е и полсекунды между их стартом).


--------------------
"Чтобы правильно задать вопрос, нужно знать большую часть ответа" (Р. Шекли)
ЖоржЖЖ
PM WWW   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
javastic
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0771 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.