С наступающим Новым годом! Форум программистов, компьютерный форум, киберфорум
Наши страницы
Java SE (J2SE)
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.83/18: Рейтинг темы: голосов - 18, средняя оценка - 4.83
Karlo_Dipetrio
0 / 0 / 0
Регистрация: 06.07.2013
Сообщений: 9
1

Спящий парикмахер. Многопоточность

09.08.2013, 22:22. Просмотров 3459. Ответов 10
Метки нет (Все метки)

Доброго времени суток, уважаемые форумчане!
Прошу вашего совета.
Начинаю осваивать Java и решил написать программку реализующую решение задачи спящего парикмахера.
Формулировка задачи:

Аналогия основана на гипотетической парикмахерской с одним парикмахером. У парикмахера есть одно рабочее место и приемная с несколькими стульями. Когда парикмахер заканчивает подстригать клиента, он отпускает клиента и затем идет в приёмную, чтобы посмотреть, есть ли там ожидающие клиенты. Если они есть, он приглашает одного из них и стрижет его. Если ждущих клиентов нет, он возвращается к своему креслу и спит в нем.
Каждый приходящий клиент смотрит на то, что делает парикмахер. Если парикмахер спит, то клиент будит его и садится в кресло. Если парикмахер работает, то клиент идет в приёмную. Если в приёмной есть свободный стул, клиент садится и ждёт своей очереди. Если свободного стула нет, то клиент уходит. Основываясь на наивном анализе, вышеупомянутое описание по идее должно гарантировать, что парикмахерская функционирует правильно с парикмахером, стригущим любого пришедшего, пока есть клиенты, и затем спящим до появления следующего клиента. На практике же существует несколько конфликтных ситуаций, которые иллюстрируют общие проблемы планирования.
Все эти конфликтные ситуации связаны с тем фактом, что действия и парикмахера, и клиента (проверка приёмной, вход в парикмахерскую, занятие места в приёмной, и т. д.) занимают неизвестное количество времени и/или могут происходить одновременно. Например, клиент может войти и заметить, что парикмахер работает, тогда он идет в приёмную. Пока он идет, парикмахер заканчивает стрижку, которую он делает и идет, чтобы проверить приемную, причём делает это быстрее направляющегося туда клиента. Так как в приёмной пока ещё никого нет (клиент ещё не дошел), он возвращается к своему месту и спит. Парикмахер теперь ждет клиента, а клиент ждет парикмахера. В другом примере два клиента могут прибыть в то же самое время, когда в приемной есть единственное свободное место. Они замечают, что парикмахер работает, идут в приёмную, и оба пытаются занять единственный стул.

Начал писать код, пока только наброски:
3 класса:
Посетитель
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package ru.mail.kdallas777.mylabs.barber;
 
public class Customer implements Runnable {
    private BarberShop barberShop;
    
    public Customer(BarberShop bShop) {
        barberShop = bShop;
    }
    
    public int checkBarber(BarberShop aBarberShop) {
        
        return aBarberShop.getBarber().getStateFlag();
    }
    
    public void run() {
        return;
    }
 
}
Парикмахерская с вложенным классом парикмахер
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
package ru.mail.kdallas777.mylabs.barber;
 
import java.util.concurrent.locks.*;
 
public class BarberShop implements Runnable {
    public static final int NUM_CHAIRS = 3;
    public static final int NUM_WORKSPACES = 1;
    
    private int customersCount;
    private int freeChairs;
    private boolean workspaceEmptyFlag;
    private Lock barberLock = new ReentrantLock();
    
    private Barber barberMan;
    
    public BarberShop() {
        customersCount = 0;
        freeChairs = NUM_CHAIRS;
        workspaceEmptyFlag = true;
        
        barberMan = new Barber();
    }
    
    public void run() {
        while(true) {
            if( workspaceEmptyFlag==false ) {
                barberMan.work();
            } else {
                barberMan.sleep();
            }
        }
    }
    
    public Barber getBarber() {
        return barberMan;
    }
    
    public class Barber {
        //boolean workFlag;
        //boolean sleepFlag;
        // barber`s state flag
        // 0 - sleep
        // 1 - work
        int stateFlag;
        
        //enum barberState {SLEEP, WORK};
        
        public Barber() {
            //workFlag = false;
            //sleepFlag = true;
            stateFlag = 0;
        }
        
        public int getStateFlag() {
            return stateFlag;
        }
        
        public boolean setStateFlag(int value) {
            if( (value == 0)||(value == 1) ) {
                stateFlag = value;
                return true;
            }
            
            return false;
        }
        
        /*
        public boolean getWorkFlag() {
            return workFlag;
        }
        
        public boolean getsleepFlag() {
            return sleepFlag;
        }
        */
        
        public void work() {
            if( !workspaceEmptyFlag ) {
                barberLock.unlock();
                stateFlag = 1;
                //sleepFlag = false;
                //workFlag = true;
                
                System.out.println("Парикмахер стрижет посетителя");
            }
        }
        
        public void sleep() {
            if( workspaceEmptyFlag ) {
                barberLock.unlock();
                stateFlag = 0;
                //workFlag = false;
                //sleepFlag = true;
                
                
                System.out.println("Парикмахер спит");
            }
        }
        
        public boolean checkCustomers() {
            barberLock.lock();
            try {
                System.out.printf("Парикмахер проверяет наличие клиентов:\n В очереди %d из %d", customersCount, NUM_CHAIRS);
                return customersCount > 0;
            }
            finally {
                barberLock.unlock();
            }
            
        }
        
    }
 
}
Проблема в следующем:
Решил использовать ReentrantLock (отсюда первый вопрос: есть ли вообще в этом смысл, не лучше ли сделать через Synchronized?)

Имеется блокировка
Java
1
private Lock barberLock = new ReentrantLock();
Я вроде как понимаю, что у посетителя и у парикмахера должно быть что-то общее, например какой-нибудь метод, что позволит их синхронизировать, но не могу понять, правильно ли я мыслю. Единственное решение, которое приходит на ум:
Сделать публичный метод getBarberLock() и через него получить блокировку в классе посетитель и использовать там же при вызове метода проверки состояния парикмахера со стороны посетителя, но в тоже время понимаю, что это не совсем разумно делать публичные методы для работы с блокировками, однако других идей нет.
Подскажите пожалуйста в каком направлении думать
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
09.08.2013, 22:22
Ответы с готовыми решениями:

"Спящий парикмахер", используя семафоры
Добрый день, подскажите если у кого есть код для задачки про спящего...

Системное программирование: программа контроля переход в спящий режим
Доброе время суток. Каким образом можно реализовать системно контроль перехода...

Многопоточность
Здравствуйте, что-то у меня не выходит ... Должно быть так А . . В А...

Многопоточность
Здравствуйте, играюсь с многопоточностью. Подскажите пожалуйста дает ли она...

Многопоточность
Если не ошибаюсь, данная вещь, которая описана ниже, называется...

10
Gepar
1182 / 538 / 77
Регистрация: 01.07.2009
Сообщений: 3,517
10.08.2013, 13:36 2
Можно же синхронизироваться по креслу, клиент пришёл и смотрит кто там в кресле есть:
если парикмахер то сганяет его, если клиент - садиться на другое кресло (если оно есть - иначе на выход). Когда состояние кресла меняеться можно будить клиентов через notify. Вот отдалённый пример в тему synchronized и объекта синхронизирующегося по другому объекту (медведь ждёт горшок), это я какому-то студенту на экзамене писал поэтому чтобы ему было понятно всё в одном классе и ну очень много комментариев, думаю будет полезно для примера.

Смысл задачи: пчёлы носят мёд в горшок (очень заботливые пчёлы - сразу в горшок), а медведь ест мёд когда горшок заполняется, до этого он спит, в этой модификации он ждёт пока пчёлы наносят все горшки с мёдом. Хотя я бы предпочёл изменить задачу чтобы пока поток медведь ждёт заполненный мёдом горшок пчёлы жалили его в мохнатую жопу, но увы и ах, задачи на экзамене составляю не я.

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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
package honeyPackage;
 
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.*;
 
 
//Горшок с мёдом
class PotWithHoney{
  String potName;
  public int count;//сколько сейчас мёда
  public static final int maxCount = 100;//сколько всего мёда влезает в горшок
 
  public PotWithHoney(String potName){
      this.potName = potName;
  }
 
  //положить мёд (для пчёлки)
  //synchronized() не пустит больше 1 пчёлки за раз (РЕАЛЗИАЦИЯ ПУНКТА 1 из доп. заданий)
  synchronized public void put(){
 
      //если горшок полный  - будим медведя
      while(isFull())
          try{
              System.out.println(potName +" заполнен!");
              notify();
              wait();
          } catch (InterruptedException e) {
              System.out.println(e);
          }
 
      //иначе пополняем горшок
      count ++;
      //каждые 10 "добавок" от пчёл в горшок выводим сообщение о том сколько мёда в горшке
      if(count%10 == 0)
          System.out.println("Пчёлы наносили " + count + "% мёда  в горшок " + potName + " ...");
  }
 
  //скушать мёд (для медведя)
  synchronized public void eat(){
      //если горшок не полный то спать
      while(!isFull())
          try{
              wait();
          } catch (InterruptedException e) {
              System.out.println(e);
          }
 
      //а если полный то жрать )
      System.out.println("Медведь проснулся и съел весь мёд в горшке " + potName +"!Ням-ням-ням!!!");
      count = 0;
      notifyAll();
  }
 
  //метод для хитрого медведя - позволяет медведю спать пока горшок наполниться
  //но не есть его сразу (чтобы потом можно было съесть сразу несколько горшков)
  synchronized public void waitForFull(){
      while(!isFull())
          try{
              wait();
          } catch (InterruptedException e) {
              System.out.println(e);
          }
  }
 
  //метод проверяет полный ли горшок
  public boolean isFull(){
      return count == maxCount;
  }
}
 
 
//пчела
class Bee extends Thread{
  private PotWithHoney pot;//горшок куда носить мёд
  private int timeSleep;
 
 
  public Bee(PotWithHoney p, int timeSleep){
      pot = p;
      this.timeSleep = timeSleep;
  }
 
  Bee(PotWithHoney p){
      this(p,50);
  }
 
  @Override
  //постоянно трудиться и носит мёд в горшок
  public void run() {
      while(true){
          pot.put();
          try {
              //после того как отнесла мёд отдыхает 50 мс
              Thread.sleep(timeSleep);
          } catch (InterruptedException e) { }
      }
  }
}
 
//медведь
class Bear extends Thread{
  List<PotWithHoney> pots;//список горшков с мёдом. Медведь ждёт пока они заполняться, а потом уже их ест
  int eatCount;//сколько раз медведь съел все горшки
 
  public Bear(List<PotWithHoney> p){
      pots = p;
  }
 
  @Override
  //постоянно спит пока его не сбудят пчёлы
  //после чего съедает мёд и засыпает
  //(поток работает постоянно)
  public void run() {
      while (true){
          //сначала ждёт пока пчёлы наносят мёда во ВСЕ горшки
          for(PotWithHoney pot : pots)
              pot.waitForFull();
          //а потом жрёт всё сразу
          for(PotWithHoney pot : pots)
              pot.eat();
 
          //увеличиваем счётчик раз сколько медведь уже съел все горшки
          eatCount++;
          if(eatCount%5 != 0)
              System.out.println("Ох и наелся же медведь. Сразу " + pots.size() + " горшка скушал, чуть не лопнул!\n");
          else
              System.out.println("Медведь таки разжирел. Ещё бы, столько жрать!");
      }
 
  }
}
 
 
public class Main {
  public static void main(String[] args){
      //создаём 3 горшка
      PotWithHoney pot1 = new PotWithHoney("Горшок 1");
      PotWithHoney pot2 = new PotWithHoney("Горшок 2");
      PotWithHoney pot3 = new PotWithHoney("Горшок 3");
 
      //создаём 3 пчелы, скорость того как они носят мёд разная (чтобы было интереснее)
      Bee bee1 = new Bee(pot1,60);
      Bee bee2 = new Bee(pot2,50);
      Bee bee3 = new Bee(pot3,55);
 
      //создаём список горшков, которые медведь будет кушать
      ArrayList<PotWithHoney> pots = new ArrayList<PotWithHoney>();
      pots.add(pot1);
      pots.add(pot2);
      pots.add(pot3);
 
      //создаём самого медведя
      Bear bear = new Bear(pots);
 
      //запускаем все потоки
      bear.start();
      bee1.start();
      bee2.start();
      bee3.start();
  }
  
    @org.junit.Test
    //тест что пчела наносит горшок за 5 секунд (размер горшка такой что должна успеть)
    public void testFullPot() {
        PotWithHoney pot1 = new PotWithHoney("Горшок 1");
        Bee bee1 = new Bee(pot1,30);
        bee1.start();
        
        try{
        Thread.sleep(5000);
        } catch(InterruptedException ex) { }
        
        int full = 100;
        assertEquals(pot1.count,full);
    }
    
    @org.junit.Test
    //тест что медведь ест мёд
    public void testEat(){
        int full = 100;
        int empty = 0;
        
        PotWithHoney pot1 = new PotWithHoney("Горшок 1");
        
        pot1.count = full;
        
        ArrayList<PotWithHoney> pots = new ArrayList<PotWithHoney>();
        pots.add(pot1);
        Bear bear = new Bear(pots);
        bear.start();
        
        try{
        Thread.sleep(1000);
        } catch(InterruptedException ex) { }
        
        //проверяем что после того как медведь был запущен горшок стал пустым
        assertEquals(pot1.count,empty);
        
    }
        
}
Добавлено через 2 минуты
Надо кстати наверное разбить таки на пару файлов и запостить в свой блог этот код, сейчас почитал свой код и посмеялся с тогдашней задачи, думаю другие форумчане тоже оценят придуманную экзаменатором задачу
1
Karlo_Dipetrio
0 / 0 / 0
Регистрация: 06.07.2013
Сообщений: 9
10.08.2013, 14:43  [ТС] 3
Спасибо большое за ответ и объяснения, сегодня попробую

Добавлено через 42 минуты
Цитата Сообщение от Gepar Посмотреть сообщение
Можно же синхронизироваться по креслу
Единственное, я не очень понял:
Я себе представляю так, мы делаем синхронизированный метод, и если к этому методу обращаемся из двух потоков одновременно, то первый поток вызвавший метод захватывает блокировку и не дает работать с этим методом другому потоку, пока не закончит сам, так?
То есть получается, мне необходимо сделать метод, например метод проверки состояния кресла и дергать его и со стороны посетителя и со стороны парикмахера?
0
Gepar
1182 / 538 / 77
Регистрация: 01.07.2009
Сообщений: 3,517
11.08.2013, 11:04 4
Karlo_Dipetrio, не совсем или же ты не правильно выразился, ты синхронизируешься не по методу, а по обхекту (хотя в данном коде выглядит как-будто мы и правда ждём пока завершиться вызов метода). Видишь вон в моей задаче медведь синхронизируеться по списку горшков (изнчально по одному горшку) с мёдом.

Добавлено через 1 минуту
Можешь кстати у Шилдта открыть раздел по многопоточности если видишь что тебе недостаёт знаний в этой теме, раздел книги всяко лучше статей в интернете и готовых примеров по которым сложнее разобраться если до этого не работал с многопоточностью.
1
Karlo_Dipetrio
0 / 0 / 0
Регистрация: 06.07.2013
Сообщений: 9
11.08.2013, 13:04  [ТС] 5
Спасибо. Я по Хорстману читал, но видимо не уловил. Кажется теперь понял. Поправьте пожалуйста если я ошибаюсь: При выполнении синхронизированного метода, захватывается блокировка объекта с этим методом и любой другой поток не сможет выполнить ни один из синхронизированных методов заблокированного объекта пока первый поток не завершит работу с методом?

Добавлено через 13 минут
Т.е., таким образом, если сделать в классе парикмахерской методы для проверки состояния кресла и для занятия кресла посетителем синхронизированными, то это обезопасит от ситуации, когда клиент может войти и заметить, что парикмахер работает, тогда он идет в приёмную. Пока он идет, парикмахер заканчивает стрижку, которую он делает и идет, чтобы проверить приемную, причём делает это быстрее направляющегося туда клиента. Так как в приёмной пока ещё никого нет (клиент ещё не дошел), он возвращается к своему месту и спит. Парикмахер теперь ждет клиента, а клиент ждет парикмахера?
0
Gepar
1182 / 538 / 77
Регистрация: 01.07.2009
Сообщений: 3,517
12.08.2013, 01:31 6
Цитата Сообщение от Karlo_Dipetrio Посмотреть сообщение
При выполнении синхронизированного метода, захватывается блокировка объекта с этим методом и любой другой поток не сможет выполнить ни один из синхронизированных методов заблокированного объекта пока первый поток не завершит работу с методом?
Да
void synchronized method(){...} == void method() { synchronized(this) {...} }

А вообще ты бы начал писать и решать задачу вот и посмотришь что получиться и как поступить
1
Karlo_Dipetrio
0 / 0 / 0
Регистрация: 06.07.2013
Сообщений: 9
12.08.2013, 01:34  [ТС] 7
Да, спасибо, сегодня уже неплохо продвинулся! Огромное спасибо за советы
0
Karlo_Dipetrio
0 / 0 / 0
Регистрация: 06.07.2013
Сообщений: 9
15.08.2013, 23:30  [ТС] 8
Вобщем делал я делал, и что-то получилось) Не судите строго, но все же есть косяк, бывает ситуация, когда парикмахер заканчивает стрижку и должен сразу же проверить очередь клиентов, но один из клиентов может вклиниться в этот момент и проверить парикмахера и увидеть, что он занят, хотя тот закончил стрижку. Я так понимаю это происходит вне синхронизированного метода, то есть ошибка не в нем, или я не правильно понимаю. вот метод run() парикмахера:
Java
1
2
3
4
5
6
7
8
9
10
@Override
        public void run() {
            while(true) {
                if( (stateFlag!=0) && (checkCustomers()) ) {
                    callCustomer();
                } else {
                    barberMan.sleep();
                }
            }
        }
у меня есть несколько идей, как например, засунуть в метод checkCustomerd() действия в зависимости от результата проверки, или же как-то засинхронизировать блок в методе run(), но мне кажется это не разумно, подскажите пожалуйста.
Вот ошибочная ситуация:
Посетитель 1 проверяет состояние парикмахера: парикмахер спит

Посетитель 1 разбудил парикмахера и сел на стрижку

Парикмахер стрижет посетителя: Посетитель 1

Парикмахер закончил стричь посетителя: Посетитель 1

Посетитель 2 проверяет состояние парикмахера: парикмахер занят работой

Посетитель 2 занял место в приемной

Парикмахер проверяет наличие клиентов: В очереди 1 из 3

Парикмахер стрижет посетителя: Посетитель 2

а вот полный код:
Парикмахерская с парикмахером
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
import java.util.concurrent.locks.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.LinkedList;
 
public class BarberShop {
    public static final int NUM_CHAIRS = 3;
    public static final int NUM_WORKSPACES = 1;
    
    // Количетсво обслуженных клиентов
    private int customersCount;
    private int leftCustomersCount;
    
    // Количество свободных кресел
    //private int freeChairs;
    
    // Флаг состояния рабочего кресал парикмахера
    // true - Кресло пусто
    // false - Кресло занято клиентом
    private boolean workspaceEmptyFlag;
    
    // Парикмахер
    private Barber barberMan;
    
    // Места в приемной
    //private List<Customer> customerList;
    private Queue<Customer> customerList = new LinkedList<Customer>();
    
    public BarberShop() {
        customersCount = 0;
        leftCustomersCount = 0;
        //freeChairs = NUM_CHAIRS;
        workspaceEmptyFlag = true;
        
        barberMan = new Barber();
    }
    
    public Queue<Customer> getCustomerList() {
        return customerList;
    }
    
    public Barber getBarber() {
        return barberMan;
    }
    
    // Занять место в приемной посетителем если есть свободные, возвращает true если удалось
    public synchronized void sitInWaitingRoom(Customer customer) {
        if( customerList.size() < NUM_CHAIRS ) {
            customerList.add(customer);
            System.out.println(customer.getCustomerName() + " занял место в приемной\n");
            notify();
            try {
                wait();
            }
            catch(InterruptedException e) {
                e.printStackTrace();
            }
        } else {
            leftCustomersCount++;
            System.out.println(customer.getCustomerName() + " ушел из парикмахерской, так как нет мест, количество необслужанных клиентов: "+ leftCustomersCount + "\n");
            notify();
            try {
                wait();
            }
            catch(InterruptedException e) {
                e.printStackTrace();
            }
        }
        
    }
    
    // Разбудить парикмахера и сесть на рабочее место если парикмахер спит
    public synchronized void sitInWorkspace(Customer customer) {
            System.out.println(customer.getCustomerName() + " разбудил парикмахера и сел на стрижку\n");
            barberMan.work(customer);
            notify();
            try {
                wait();
            }
            catch(InterruptedException e) {
                e.printStackTrace();
            }
    }
    
    // Проверка наличия посетителей со стороны парикмахера
    public synchronized boolean checkCustomers() {
        System.out.printf("Парикмахер проверяет наличие клиентов: В очереди %d из %d\n\n", customerList.size(), NUM_CHAIRS);
        return !customerList.isEmpty();
    }
    
    // Проверка состояния парикмахера со стороны клиента
    // 0 - sleep
    // 1 - work
    public synchronized int checkBarber(Customer customer) {
        System.out.print(customer.getCustomerName() + " проверяет состояние парикмахера:");
        
        if( barberMan.getStateFlag() == 0 ){
            System.out.println(" парикмахер спит\n");
        } else {
            System.out.println(" парикмахер занят работой\n");
        }
        
        return barberMan.getStateFlag();
    }
    
    // Позвать клиента из очереди в приемной если есть, иначе спать, возвращает true если удалось
    public synchronized void callCustomer() {
        if( !customerList.isEmpty() ) {
            barberMan.work(customerList.poll());
        } else {
            barberMan.sleep();
        }
    }
    
    public class Barber implements Runnable {
        // Время одной стрижки в мс
        public static final int WORK_TIME = 10000;
        
        // barber`s state flag
        // 0 - sleep
        // 1 - work
        // 2 - check
        int stateFlag;
        
        //enum barberState {SLEEP, WORK};
        
        public Barber() {
            stateFlag = 2;
        }
        
        @Override
        public void run() {
            while(true) {
                if( (stateFlag!=0) && (checkCustomers()) ) {
                    callCustomer();
                } else {
                    barberMan.sleep();
                }
            }
        }
        
        public int getStateFlag() {
            return stateFlag;
        }
        
        public boolean setStateFlag(int value) {
            if( (value == 0)||(value == 1) ) {
                stateFlag = value;
                return true;
            }
            
            return false;
        }
        
        public synchronized void work(Customer customer) {
            stateFlag = 1;
                
            System.out.printf("Парикмахер стрижет посетителя: %s\n\n", customer.getCustomerName());
            try {
                Thread.sleep(WORK_TIME);
                //wait(WORK_TIME);
                System.out.printf("Парикмахер закончил стричь посетителя: %s\n\n", customer.getCustomerName());
                customersCount++;
                stateFlag = 2;
                notify();
            }
            catch(InterruptedException e) {
                e.printStackTrace();
            }
        }
        
        public synchronized void sleep() {
            if( stateFlag!=0 ) {
                stateFlag = 0;
                
                System.out.println("Парикмахер спит\n");
                try {
                    wait();
                }
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }   
            
            notifyAll();
        }
        
    }
 
}
Класс посетитель:
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
public class Customer implements Runnable {
    private static int id = 1;
    private String customerName;
    private BarberShop barberShop;
 
    public Customer(BarberShop bShop, String name) {
        customerName = name + id;
        barberShop = bShop;
        id++;
    }
    
    public String getCustomerName() {
        return customerName;
    }
    
    public int check() {
        return barberShop.checkBarber(this);
    }
    
    @Override
    public void run() {
        if( check() == 0 ) {
            barberShop.sitInWorkspace(this);
        } else {
            barberShop.sitInWaitingRoom(this);
        }
    }
}
Тестовый класс:
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
public class BarbaerShopTest {
 
    public static void main(String args[]) {
        // Создаем парикмахерскую с парикмахером
        BarberShop barberShopSim = new BarberShop();
        
        Thread barberThread = new Thread(barberShopSim.getBarber());
        barberThread.start();   
        
        while(true) {
            Thread customerThread = new Thread(new Customer(barberShopSim, "Посетитель "));
            customerThread.start();
            
            try {
                Thread.sleep( (int)(Math.random()*20000) );
            }
            catch(InterruptedException e) {
                e.printStackTrace();
            }
        }
            
    }
 
}
0
Karlo_Dipetrio
0 / 0 / 0
Регистрация: 06.07.2013
Сообщений: 9
18.08.2013, 23:10  [ТС] 9
Спасибо за ответы, Ваш пример с медведем очень здорово помог!) Gepar, Вроде все удалось) Переделал код
Тему можно закрыть
0
easybudda
Модератор
Эксперт CЭксперт С++
10158 / 6062 / 1526
Регистрация: 25.07.2009
Сообщений: 11,498
26.08.2013, 17:22 10
Задачка-то интересная, давно хотел сделать, да всё руки не доходили... Не совсем комильфо получилось - после закрытия ещё кто-то ждать усаживается, но в принципе интересно - приходят, стригутся...
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
package easybudda.examples.barbershop;
 
public class Barber implements Runnable {
    private Barbershop barbershop;
    private int dayPayment;
    
    public Barber(Barbershop barbershop) {
        this.barbershop = barbershop;
        this.dayPayment = 0;
    }
 
    @Override
    public void run() {
        System.out.println("Парикмахер спит в ожидании клиентов");
        while ( barbershop.isOpen() ) {
            Customer customer = barbershop.getCustomer();
            System.out.println("Парикмахер работает...");
            System.out.println("Клиент: " + customer.getName());
            System.out.println("Причёска: " + customer.getHairstyle());
            try {
                Thread.sleep(customer.getHairstyle().getTime());
            }
            catch ( InterruptedException e) {
                System.out.println("Не достригли бедолагу!");
            }
            int payment = customer.getHairstyle().getPrice();
            dayPayment += payment;
            System.out.println("Парикмахер заработал $" + payment);
        
            if ( barbershop.customersWaiting() ) {
                System.out.println("Парикмахер берёт следующего клиента из очереди");
                barbershop.serveCustomer(barbershop.getFromQueue());
            }
            else {
                System.out.println("Никого нет, парикмахер чистит место и спит");
                barbershop.cleanWorkplace();
            }
        }
        
        System.out.println("Парикмахер заработал за день $" + dayPayment);
    }
}
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
package easybudda.examples.barbershop;
 
import java.util.Queue;
import java.util.LinkedList;
 
public class Barbershop {
    private boolean open;
    private int maxPlaces;
    private Queue<Customer> customersQueue;
    private Customer currentCustomer;
    
    public Barbershop(int max_places) {
        maxPlaces = max_places;
        open = true;
        customersQueue = new LinkedList<Customer>();
        currentCustomer = null;
    }
    
    public synchronized boolean isOpen() {
        return open;
    }
    
    public synchronized void close() {
        open = false;
        notifyAll();
    }
    
    public synchronized boolean customersWaiting() {
        return ! customersQueue.isEmpty();
    }
    
    public synchronized boolean havePlaceToWait() {
        return customersQueue.size() < maxPlaces;
    }
    
    public synchronized boolean readyToService() {
        return currentCustomer == null;
    }
    
    public synchronized boolean workplaceOccupied() {
        return currentCustomer != null; 
    }
    
    public synchronized void serveCustomer(Customer customer) {
        currentCustomer = customer;
        notifyAll();
    }
    
    public synchronized void cleanWorkplace() {
        currentCustomer = null;
    }
    
    public synchronized void addToQueue(Customer customer) {
        customersQueue.add(customer);
    }
    
    public synchronized Customer getFromQueue() {
        return customersQueue.remove();
    }
    
    public synchronized Customer getCustomer() {
        while ( readyToService() ) {
            try {
                wait();
            }
            catch ( InterruptedException e ) {
                System.out.println("Прервано ожидание клиентов");
            }
        }
        return currentCustomer;
    }
}
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
package easybudda.examples.barbershop;
 
public class BarbershopModel {
    private static final int MAX_PLACES = 3;
    private static final long WORKING_TIME = 60000L;
    private static final int CUSTOMERS_FREQUENCY = 5000;
    
    public static void main(String[] args) {
        Barbershop barbershop = new Barbershop(MAX_PLACES);
        Barber barber = new Barber(barbershop);
        Customersgate gate = new Customersgate(barbershop, CUSTOMERS_FREQUENCY);
        
        Thread barberThread = new Thread(barber);
        barberThread.start();
        
        Thread gateThread = new Thread(gate);
        gateThread.start();
        
        try {
            Thread.sleep(WORKING_TIME);
        }
        catch ( InterruptedException e ) {
            System.out.println("Главный поток прерван");
        }
        
        System.out.println("Парикмахерская закрывается");
        barbershop.close();
        
        try {
            barberThread.join();
            gateThread.join();
        }
        catch ( InterruptedException e ) {
            System.out.println("Не дождались всех потоков");
        }
    }
 
}
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package easybudda.examples.barbershop;
 
public class Customer {
    private String name;
    private Hairstyle hairstyle;
    
    public Customer(String name, Hairstyle hairstyle) {
        this.name = name;
        this.hairstyle = hairstyle;
    }
    
    public String getName() {
        return name;
    }
    
    public Hairstyle getHairstyle() {
        return hairstyle;
    }
}
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package easybudda.examples.barbershop;
 
import java.util.Random;
 
public class CustomersFactory {
    private static String [] names = { "Иван", "Василий", "Фёдор", "Макар", "Семён", "Пафнутий", "Пётр" };
    private static String [] patronymics = { "Альфредович", "Поликарпович", "Егорович", "Назарович", "Фомич", "Никитич" };
    private static Hairstyle [] hairstyles = Hairstyle.values();
    private static Random rand = new Random();
    
    private CustomersFactory() {}
    
    public static Customer getCustomer() {
        return new Customer(names[rand.nextInt(names.length)] + " " + patronymics[rand.nextInt(patronymics.length)], hairstyles[rand.nextInt(hairstyles.length)]);
    }
 
}
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
package easybudda.examples.barbershop;
 
import java.util.Random;
 
public class Customersgate implements Runnable {
    private Barbershop barbershop;
    private Random rand;
    private int frequency;
    
    public Customersgate(Barbershop bs, int freq) {
        barbershop = bs;
        frequency = freq;
        rand = new Random();
    }
 
    @Override
    public void run() {
        while ( barbershop.isOpen() ) {
            try {
                Thread.sleep(rand.nextInt(frequency));
            }
            catch ( InterruptedException e ) {
                System.out.println("Нежданчиком клиент явился...");
            }
            Customer customer = CustomersFactory.getCustomer();
            System.out.println("Приходит " + customer.getName());
            if ( barbershop.customersWaiting() ) {
                System.out.println(customer.getName() + " видит очередь");
                if ( barbershop.havePlaceToWait() ) {
                    System.out.println(customer.getName() + " видит место, садится ждать");
                    barbershop.addToQueue(customer);
                }
                else {
                    System.out.println(customer.getName() + " видит, что мест нет, и уходит");
                    customer = null;
                }
            }
            else {
                if ( barbershop.readyToService() ) {
                    System.out.println(customer.getName() + " садится в кресло");
                    barbershop.serveCustomer(customer);
                }
                else {
                    System.out.println(customer.getName() + " видит, что кто-то стрижётся, садится в очередь");
                    barbershop.addToQueue(customer);
                }
            }
        }
    }
 
}
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package easybudda.examples.barbershop;
 
public enum Hairstyle {
    Iroquois(25, 3000), Polubox(10, 1800), Kotovsky(5, 1000), Gorshok(15, 2000), Afro(50, 5000), Dreads(40, 4500);
    
    private int price;
    private long time;
    
    Hairstyle(int price, long time) {
        this.price = price;
        this.time = time;
    }
    
    public int getPrice() {
        return price;
    }
    
    public long getTime() {
        return time;
    }
}
1
Karlo_Dipetrio
0 / 0 / 0
Регистрация: 06.07.2013
Сообщений: 9
26.08.2013, 17:44  [ТС] 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
package ru.mail.kdallas777.mylabs.barber;
 
public class Customer implements Runnable {
    // Номер посетителя
    private static int id = 1;
    
    // Имя посетителя
    private String customerName;
    
    // Парикмахерская
    private BarberShop barberShop;
 
    public Customer(BarberShop bShop, String name) {
        customerName = name + id;
        barberShop = bShop;
        id++;
    }
    
    public String getCustomerName() {
        return customerName;
    }
    
    @Override
    public void run() {
        barberShop.sitInWorkspace(this);
    }
}
Парикмахерская с парикмахером:
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
package ru.mail.kdallas777.mylabs.barber;
 
import java.util.concurrent.locks.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.LinkedList;
 
public class BarberShop {
    // Количество мест в приемной
    public static final int NUM_CHAIRS = 3;
    
    // Количество рабочих мест(парикмахеров)
    public static final int NUM_WORKSPACES = 1;
    
    // Время одной стрижки в мс
    public static final int WORK_TIME = 10000;
            
    // Рабочее место парикмахера
    private Customer barberWorkspace;
    
    private enum BarberState {
        SLEEP, WORK, NOTHING
    }
    
    // Состояние парикмахера
    BarberState stateFlag;
    
    // Количетсво обслуженных клиентов
    private int customersCount;
    
    // Количество необслужанных клиентов
    private int leftCustomersCount;
    
    // Парикмахер
    private Barber barberMan;
    
    // Места в приемной
    private Queue<Customer> customerList = new LinkedList<Customer>();
    
    public BarberShop() {
        customersCount = 0;
        leftCustomersCount = 0;
        
        barberMan = new Barber();
    }
    
    //=============================================
    // Методы управления данными
    //=============================================
    public Queue<Customer> getCustomerList() {
        return customerList;
    }
    //---------------------------------------------
    public Barber getBarber() {
        return barberMan;
    }
    //=============================================
    // Методы посетителей
    //=============================================
    // Занять место в приемной посетителем если есть свободные, возвращает true если удалось
    private void sitInWaitingRoom(Customer customer) {
        if( customerList.size() < NUM_CHAIRS ) {
            customerList.add(customer);
            System.out.println(customer.getCustomerName() + " занял место в приемной\n");
        } else {
            leftCustomersCount++;
            System.out.println(customer.getCustomerName() + " ушел из парикмахерской, так как нет мест, количество необслужанных клиентов: "+ leftCustomersCount + "\n");
        }
    }
    //---------------------------------------------
    // Разбудить парикмахера и сесть на рабочее место если парикмахер спит
    public synchronized void sitInWorkspace(Customer customer) {
        if( checkBarber(customer) == BarberState.SLEEP ) {
            System.out.println(customer.getCustomerName() + " разбудил парикмахера и сел на стрижку\n");
            barberWorkspace = customer;
            stateFlag = BarberState.WORK;
        } else {
            sitInWaitingRoom(customer);
        }
        
        try {
            notify();
            wait();
        }
        catch(InterruptedException e) {
            e.printStackTrace();
        }
        
    }
    //---------------------------------------------
    // Проверка состояния парикмахера со стороны клиента
    // 0 - sleep
    // 1 - work
    public BarberState checkBarber(Customer customer) {
        System.out.print(customer.getCustomerName() + " проверяет состояние парикмахера:");
        
        if( stateFlag == BarberState.SLEEP ){
            System.out.println(" парикмахер спит\n");
        } else {
            System.out.println(" парикмахер занят работой\n");
        }
        
        return stateFlag;
    }
    //=============================================
    // Методы парикмахера
    //=============================================
    // Проверка наличия посетителей со стороны парикмахера
    public synchronized boolean checkCustomers() {
        System.out.printf("Парикмахер проверяет наличие клиентов: В очереди %d из %d\n\n", customerList.size(), NUM_CHAIRS);
        return !customerList.isEmpty();
    }
    //---------------------------------------------
    public synchronized void work() {
        while( isWorkspaceEmpty() ) {
            try {
                sleep();
                wait();
            }
            catch(InterruptedException e) {
                e.printStackTrace();
            }
        }
        
        while( !isWorkspaceEmpty() ) {
            if( stateFlag != BarberState.WORK)
                stateFlag = BarberState.WORK;
            
            System.out.printf("Парикмахер стрижет посетителя: %s\n\n", barberWorkspace.getCustomerName());
            
            try {
                wait(WORK_TIME);
            }
            catch(InterruptedException e) {
                e.printStackTrace();
            }
            
            System.out.printf("Парикмахер закончил стричь посетителя: %s\n\n", barberWorkspace.getCustomerName());
            customersCount++;
            stateFlag = BarberState.NOTHING;
            resetBarberWorkspace();
            callCustomer();
        }
    }
    //---------------------------------------------
    public synchronized void sleep() {
        if( stateFlag != BarberState.SLEEP ) {
            stateFlag = BarberState.SLEEP;
            
            System.out.println("Парикмахер спит\n");
        }   
    }
    //---------------------------------------------
    private boolean isWorkspaceEmpty() {
        return barberWorkspace == null;
    }
    //---------------------------------------------
    private void resetBarberWorkspace() {
        barberWorkspace = null;
    }
    //---------------------------------------------
    // Позвать клиента из очереди в приемной если есть, иначе спать, возвращает true если удалось
    private synchronized void callCustomer() {
        if( checkCustomers() ) {
            barberWorkspace = customerList.poll();
        } 
    }
    //---------------------------------------------
    // Класс парикмахер
    public class Barber implements Runnable {
        public Barber() {
            stateFlag = BarberState.NOTHING;
        }
        
        @Override
        public void run() {
            while(true) {
                work();
            }
        }
        
    }
 
}
Тест:
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
package ru.mail.kdallas777.mylabs.barber;
 
public class BarbaerShopTest {
 
    public static void main(String args[]) {
        // Создаем парикмахерскую с парикмахером
        BarberShop barberShopSim = new BarberShop();
        
        Thread barberThread = new Thread(barberShopSim.getBarber());
        barberThread.start();   
        
        while(true) {
            Thread customerThread = new Thread(new Customer(barberShopSim, "Посетитель "));
            customerThread.start();
            
            try {
                Thread.sleep( (int)(Math.random()*10000) );
            }
            catch(InterruptedException e) {
                e.printStackTrace();
            }
        }
            
    }
 
}
Правда не совсем красиво в плане организации кода) но работает
0
26.08.2013, 17:44
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
26.08.2013, 17:44

Многопоточность
Здравствуйте! Есть код public static void main(String args) throws...

Многопоточность
Здравствуйте! Подскажите, где почитать о концепции применения многопоточности?...

Многопоточность
Добрый день, уважаемые гуру многопоточного программирование. Если Вас не...


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

Или воспользуйтесь поиском по форуму:
11
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru