Форум программистов, компьютерный форум, киберфорум
Java SE (J2SE)
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.81/21: Рейтинг темы: голосов - 21, средняя оценка - 4.81
2 / 2 / 0
Регистрация: 22.11.2013
Сообщений: 101

Обедающие философы, уменьшить возможность возникновения deadlock-а

07.10.2016, 12:54. Показов 4395. Ответов 11
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Есть программа, которая решает задачу обедающих философов.
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
public class Phil {
    int pos; 
      Fork left; 
      Fork right; 
      int eatCount = 0; 
      long waitTime = 0; 
      long startWait; 
 
      Random rnd = new Random(); 
      public Phil (int pos, Fork left, Fork rigth){ 
      this.pos = pos; 
      this.left = left; 
      this.right = rigth; 
      } 
      
      public void eat(){ 
      waitTime+=System.currentTimeMillis()+startWait; 
      System.out.println("Философ "+pos+" ест"); 
      try{ 
       Thread.sleep(rnd.nextInt(100)); 
      } catch (InterruptedException e){ 
       e.printStackTrace(); 
      } 
      eatCount++; 
      System.out.println("Философ "+pos+" поел"); 
      } 
          public void think(){ 
       System.out.println("Философ "+pos+" думает"); 
       try{ 
        Thread.sleep(rnd.nextInt(100)); 
       } catch (InterruptedException e){ 
        e.printStackTrace(); 
       } 
       System.out.println("Философ "+pos+" проголодался"); 
       startWait=System.currentTimeMillis(); 
      }
}
 
public class MyPhil extends Phil implements Runnable { 
  volatile boolean stopFlag = false; 
  public MyPhil(int pos, Fork left, Fork rigth) { 
  super(pos, left, rigth); 
  } 
  
  public void run() { 
  while(!stopFlag){ 
   think(); 
   synchronized(left){ 
       } 
   synchronized(right){ 
 
     eat(); 
   } 
  } 
  System.out.println("Философ "+pos+" stop"); 
  } 
  
  public static void main(String[] args) throws Exception{ 
  int count = 5; 
  MyPhil[] phils = new MyPhil[count]; 
  Fork last = new Fork(); 
  Fork left = last; 
  for (int i=0; i<count; i++){ 
   Fork right=(i==count-1)? last: new Fork(); 
   phils[i] = new MyPhil (i,left,right); 
   left = right; 
  } 
  Thread[] threads = new Thread [count]; 
  for (int i=0; i<count; i++){ 
   threads[i] = new Thread (phils[i]); 
 
   threads[i].start(); 
  } 
  Thread.sleep(60000); 
  for (MyPhil phil: phils){ 
   phil.stopFlag = true; 
  } 
  for (Thread thread:threads){ 
   thread.join(); 
  } 
  for (MyPhil phil: phils){ 
   System.out.println("Философ "+phil.pos+" поел "+phil.eatCount+" раз и прождал "+phil.waitTime); 
   phil.stopFlag = true; 
  } 
  } }
Подскажите, пожалуйста, как можно оптимизировать этот код, чтобы уменьшить возможность возникновения ситуации deadlock(взаимная блокировка)?
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
07.10.2016, 12:54
Ответы с готовыми решениями:

Обедающие философы
Добрый вечер! Возник такой вот вопрос: Есть стандартная задача с обедающими философами, описанная в книге Таненбаума. Но...

Обедающие философы
Здравствуйте участники форума я на форуме нашел программу про обедающих философов вот её исходники using System; using...

Обедающие философы
Всем привет. Нужна помощь в решении задач об обедающих философах с помощью семафоров, мониторов и блокировки. Также нужно добавить главный...

11
 Аватар для HighPredator
6045 / 2160 / 753
Регистрация: 10.12.2010
Сообщений: 6,005
Записей в блоге: 3
07.10.2016, 16:34
А в каком кейсе текущая имплементация позволяет схватить дедлок? Что-то из кода не пойму..
1
2 / 2 / 0
Регистрация: 22.11.2013
Сообщений: 101
09.10.2016, 14:36  [ТС]
Вероятность дедлока увеличивается, если в функциях eat и think убрать sleep(). Подскажите, пожалуйста, что нужно изменить?
0
 Аватар для HighPredator
6045 / 2160 / 753
Регистрация: 10.12.2010
Сообщений: 6,005
Записей в блоге: 3
10.10.2016, 08:06
Ну я бы сделал так:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public class MyPhil extends Phil implements Runnable {
    private boolean stopFlag = false;
 
    private volatile Object volatileMutex;
 
    public MyPhil(int pos, Fork left, Fork right) {
        super(pos, left, right);
    }
 
    @Override
    public void run() {
        while (!getStopFlag()) {
            think();
            synchronized (left) {
            }
            synchronized (right) {
                eat();
            }
        }
        System.out.println("Философ " + pos + " stop");
    }
 
    public void stop() {
        synchronized (mutex()) {
            stopFlag = true;
        }
    }
 
    private boolean getStopFlag() {
        synchronized (mutex()) {
            return stopFlag;
        }
    }
 
    private Object mutex() {
        Object mutex = volatileMutex;
        if (mutex == null) {
            synchronized (this) {
                mutex = volatileMutex;
                if (mutex == null) {
                    mutex = new Object();
                    volatileMutex = mutex;
                }
            }
        }
        return mutex;
    }
}
1
2 / 2 / 0
Регистрация: 22.11.2013
Сообщений: 101
10.10.2016, 16:39  [ТС]
Спасибо огромное! А можете объяснить принцип работы private Object mutex()? Насколько я поняла, это взаимное исключение?
0
 Аватар для HighPredator
6045 / 2160 / 753
Регистрация: 10.12.2010
Сообщений: 6,005
Записей в блоге: 3
10.10.2016, 16:53
Цитата Сообщение от Линда95 Посмотреть сообщение
это взаимное исключение?
Не понял, что вы под этим понимаете. Это специальный мьютекс -- объект по которому будет идти блокировка доступа. Он спроектирован так (сейчас могу неточно объяснить, ибо сам новичок в джаве, так что терминология достаточно новая), чтобы гарантировать детерминированное состояние в среде конкурентного доступа. На нем фиксируется монитор. Механизм работы в принципе вам станет ясен, если вы по шагам каждую инструкцию рассмотрите.
1
Эксперт Java
 Аватар для turbanoff
4094 / 3828 / 745
Регистрация: 18.05.2010
Сообщений: 9,331
Записей в блоге: 12
10.10.2016, 19:21
HighPredator, Зачем все эти пляски с ленивой инициализацией volatileMutex?
Обычно лок объявляют как
Java
1
private final Object mutext = new Object();
Вроде философ может есть только когда обе вилки у него, а у вас он одну отпускает, перед тем как взяться за вторую. synchronized (left) и synchronized (right) должны быть вложены друг в друга.
1
 Аватар для HighPredator
6045 / 2160 / 753
Регистрация: 10.12.2010
Сообщений: 6,005
Записей в блоге: 3
10.10.2016, 23:03
Цитата Сообщение от turbanoff Посмотреть сообщение
Зачем все эти пляски с ленивой инициализацией volatileMutex?
Увидел у гугла, понравилось, пользую везде И это вроде не ленивая инициализация, а double-checking locking idiom если не ошибаюсь.
0
2 / 2 / 0
Регистрация: 22.11.2013
Сообщений: 101
11.10.2016, 18:23  [ТС]
Цитата Сообщение от turbanoff Посмотреть сообщение
synchronized (left) и synchronized (right) должны быть вложены друг в друга.
То есть должно получиться так?

Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 public void run() {
        while (!getStopFlag()) {
            think();
            synchronized (left) {
                System.out.println("Философ "+pos+" левая вилка");
                synchronized (right) {
                System.out.println("Философ "+pos+" правая вилка");
                eat();
            }
            }
           
        }
        System.out.println("Философ " + pos + " stop");
    }
0
Эксперт Java
 Аватар для turbanoff
4094 / 3828 / 745
Регистрация: 18.05.2010
Сообщений: 9,331
Записей в блоге: 12
11.10.2016, 18:29
Линда95, да. eat можно вызывать только когда оба лока захвачены
Но, вот если так прямо сделать - то в вашем коде будет возможен deadlock.
Нужно хитро захватывать локи, чтобы такого не было.
1
2 / 2 / 0
Регистрация: 22.11.2013
Сообщений: 101
12.10.2016, 19:31  [ТС]
Цитата Сообщение от turbanoff Посмотреть сообщение
Нужно хитро захватывать локи, чтобы такого не было.
А каким образом это можно сделать, не подскажете?
0
Эксперт Java
 Аватар для turbanoff
4094 / 3828 / 745
Регистрация: 18.05.2010
Сообщений: 9,331
Записей в блоге: 12
12.10.2016, 21:29
Лучший ответ Сообщение было отмечено turbanoff как решение

Решение

На википедии описаны возможные решения - https://ru.wikipedia.org/wiki/Проблема_обедающих_философов
Вот решение с официантом:
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
class Fork {
}
 
class Waiter {
    private final Set<Fork> usedForks = Collections.newSetFromMap(new IdentityHashMap<>());
 
    void letMeEat(Fork a, Fork b, Runnable eat) {
        synchronized (usedForks) {
            while (usedForks.contains(a) || usedForks.contains(b)) {
                try {
                    usedForks.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            usedForks.add(a);
            usedForks.add(b);
        }
        synchronized (a) {
            synchronized (b) {
                eat.run();
            }
        }
        synchronized (usedForks) {
            usedForks.remove(a);
            usedForks.remove(b);
            usedForks.notifyAll();
        }
    }
}
 
class MyPhil implements Runnable {
    volatile boolean stopFlag = false;
    int pos;
    Fork left;
    Fork right;
    private final Waiter waiter;
    int eatCount = 0;
    long waitTime = 0;
    long startWait;
    Random rnd = new Random();
 
    public MyPhil(int pos, Fork left, Fork right, Waiter waiter) {
        this.pos = pos;
        this.left = left;
        this.right = right;
        this.waiter = waiter;
    }
 
    public void run() {
        while (!stopFlag) {
            think();
            waiter.letMeEat(left, right, () -> {
                if (Thread.holdsLock(left) && Thread.holdsLock(right)) {
                    eat();
                } else {
                    throw new RuntimeException("Waiter is a liar!");
                }
            });
        }
        System.out.println("Философ " + pos + " stop");
    }
 
    public static void main(String[] args) throws Exception {
        int count = 5;
        Fork[] forks = new Fork[count];
        for (int i = 0; i < forks.length; i++) {
            forks[i] = new Fork();
        }
        MyPhil[] phils = new MyPhil[count];
        Waiter waiter = new Waiter();
        for (int i = 0; i < count; i++) {
            Fork left = forks[i];
            Fork right = (i == count - 1) ? forks[0] : forks[i + 1];
            phils[i] = new MyPhil(i, left, right, waiter);
        }
        Thread[] threads = new Thread[count];
        for (int i = 0; i < count; i++) {
            threads[i] = new Thread(phils[i]);
            threads[i].start();
        }
        Thread.sleep(60000);
        for (MyPhil phil : phils) {
            phil.stopFlag = true;
        }
        for (Thread thread : threads) {
            thread.join();
        }
        for (MyPhil phil : phils) {
            System.out.println("Философ " + phil.pos + " поел " + phil.eatCount + " раз и прождал " + phil.waitTime);
        }
    }
 
    public void eat() {
        waitTime += System.currentTimeMillis() + startWait;
        System.out.println("Философ " + pos + " ест");
        try {
            Thread.sleep(rnd.nextInt(100));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        eatCount++;
        System.out.println("Философ " + pos + " поел");
    }
 
    public void think() {
        System.out.println("Философ " + pos + " думает");
        try {
            Thread.sleep(rnd.nextInt(100));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Философ " + pos + " проголодался");
        startWait = System.currentTimeMillis();
    }
}
2
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
12.10.2016, 21:29
Помогаю со студенческими работами здесь

Процессы, Обедающие философы
Здравствуйте! Нужна помощь с задачей о обедающих философах сделанная не на потоках как здесь...

Обедающие философы, Critical Section
Задача: Есть 5 философов. В столовой расположен круглый стол, вокруг которого расставлены 5 стульев. На столе находится одна большая...

Обедающие философы, перевод с Delphi
«Проблема обедающих философов» Программная реализация задачи на языке Delphi, нужно перевести в с# windows forms main.pas unit...

Обедающие философы. Решение методом монитора
Здравствуйте. Ищу решения проблемы обедающих философов методом монитора( он же официант, арбитр и т.д.) Есть у кого готовый код?


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
12
Ответ Создать тему
Новые блоги и статьи
Автозаполнение реквизита при выборе элемента справочника
Maks 27.03.2026
Программный код из решения ниже на примере нетипового документа "ЗаявкаНаРемонтСпецтехники" разработанного в конфигурации КА2. При выборе "Спецтехники" (Тип Справочник. Спецтехника), заполняется. . .
Сумматор с применением элементов трёх состояний.
Hrethgir 26.03.2026
Тут. https:/ / fips. ru/ EGD/ ab3c85c8-836d-4866-871b-c2f0c5d77fbc Первый документ красиво выглядит, но без схемы. Это конечно не даёт никаких плюсов автору, но тем не менее. . . всё может быть. . .
Автозаполнение реквизитов при создании документа
Maks 26.03.2026
Программный код из решения ниже размещается в модуле объекта документа, в процедуре "ПриСозданииНаСервере". Алгоритм проверки заполнения реализован для исключения перезаписи значения реквизита,. . .
Команды формы и диалоговое окно
Maks 26.03.2026
1. Команда формы "ЗаполнитьЗапчасти". Программный код из решения ниже на примере нетипового документа "ЗаявкаНаРемонтСпецтехники" разработанного в конфигурации КА2. В качестве источника данных. . .
Кому нужен AOT?
DevAlt 26.03.2026
Решил сделать простой ланчер Написал заготовку: dotnet new console --aot -o UrlHandler var items = args. Split(":"); var tag = items; var id = items; var executable = args;. . .
Отправка уведомления на почту при создании или изменении элементов справочника
Maks 24.03.2026
Программная отправка письма электронной почты на примере типового справочника "Склады" в конфигурации БП3. Перед реализацией необходимо выполнить настройку системной учетной записи электронной. . .
модель ЗдравоСохранения 5. Меньше увольнений- больше дохода!
anaschu 24.03.2026
Теперь система здравосохранения уменьшает количество увольнений. 9TO2GP2bpX4 a42b81fb172ffc12ca589c7898261ccb/ https:/ / rutube. ru/ video/ a42b81fb172ffc12ca589c7898261ccb/ Слева синяя линия -. . .
Midnight Chicago Blues
kumehtar 24.03.2026
Такой Midnight Chicago Blues, знаешь?. . Когда вечерние улицы становятся ночными, а ты не можешь уснуть. Ты идёшь в любимый старый бар, и бармен наливает тебе виски. Ты смотришь на пролетающие. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru