|
| 1 | +# Примитивы синхронизации |
| 2 | + |
| 3 | +В предыдущем упражнении наши потоки работали независимо друг от друга. В реальности обычно ситуация иная. Несколько потоков должны одновременно работать с одним ресурсом и менять его. Для этого потоки должны взаимодействовать между собой, должны быть синхронизированы. Представьте ситуацию, что нескольким людям нужно обсудить некоторую проблему. Чтобы обсуждение не превратилось в хаос и люди могли слышать друг друга, одновременно должен говорить только один человек. В программировании же существует специальное понятие – мьютекс. Задача мьютекса – обеспечить, чтобы доступ к разделяемому объекту был в определённое время только у одного потока. Если Поток-1 захватил ресурс, остальные потоки не смогут получить к нему доступ и будут вынуждены ждать, пока Поток-1 не освободит ресурс |
| 4 | + |
| 5 | +## Ссылки |
| 6 | + |
| 7 | +* [Ключевое слово synchronized](https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html) |
| 8 | +* [Пример использования ключевого слова synchronized](https://www.baeldung.com/java-synchronized) |
| 9 | + |
| 10 | +## src/main/java/exercise/SafetyList.java |
| 11 | + |
| 12 | +Вам предстоит написать собственную потокобезопасную реализацию листа. Потокобезопасность этого листа заключается в том, что он может исправно функционировать при использовании его из нескольких потоков одновременно. То есть он должен обеспечивать правильный доступ нескольких потоков к разделяемым данным. |
| 13 | +Для упрощения наша реализация будет работать только с целыми числами и будет включать далеко не все методы, которые есть в интерфейсе `List`. Для реализации листа используйте массив. |
| 14 | + |
| 15 | +## Задачи |
| 16 | + |
| 17 | +* Допишите содержимое класса `SafetyList`, который представляет собой потокобезопасную реализацию листа. Добавьте в класс необходимые свойства. |
| 18 | + |
| 19 | +* Создайте публичный метод `add()`, который будет добавлять новый элемент в лист. Именно у этого метода мы должны ограничить выполнение. Сделайте так, чтобы метод мог выполняться только одним потоком одновременно. |
| 20 | + |
| 21 | +* Создайте публичный метод `get()`, который будет возвращать элемент листа по его индексу |
| 22 | + |
| 23 | +* Создайте публичный метод `getSize()`, который будет возвращать количество элементов в листе |
| 24 | + |
| 25 | +```java |
| 26 | +SafetyList list = new SafetyList(); |
| 27 | +list.add(5); |
| 28 | +list.add(7); |
| 29 | +list.get(0); // 5 |
| 30 | +list.get(1); // 7 |
| 31 | +list.getSize(); // 2 |
| 32 | +``` |
| 33 | + |
| 34 | +## src/main/java/exercise/ListThread.java |
| 35 | + |
| 36 | +В этом файле мы определим поток, который будет добавлять элементы в лист |
| 37 | + |
| 38 | +## Задачи |
| 39 | + |
| 40 | +* В файле создайте класс `ListThread`, который будет представлять собой поток. |
| 41 | +* Определите в классе конструктор, который принимает в качестве аргумента нашу реализацию листа `SafetyList` |
| 42 | +* Сделайте так, чтобы при запуске поток добавлял в переданный лист 1000 любых целых чисел. Перед добавлением каждого элемента поток должен спать в течение одной 1 миллисекунды |
| 43 | + |
| 44 | +```java |
| 45 | +// Создаём лист |
| 46 | +SafetyList list = new SafetyList(); |
| 47 | + |
| 48 | +// Создаём поток, передав туда созданный лист |
| 49 | +Thread thread = new Thread(new ListThread(list)); |
| 50 | + |
| 51 | +// Запускаем поток |
| 52 | +thread.start(); |
| 53 | + |
| 54 | +// Работает примерно 1 секунду (1000 элементов * 1 мс) |
| 55 | + |
| 56 | +// Дожидаемся его окончания |
| 57 | +thread.join(); |
| 58 | + |
| 59 | +// Поток добавил в лист 1000 элементов |
| 60 | +list.getSize(); // 1000 |
| 61 | +``` |
| 62 | + |
| 63 | +## src/main/java/exercise/App.java |
| 64 | + |
| 65 | +## Задачи |
| 66 | + |
| 67 | +* В методе `main()` создайте экземпляр потокобезопасного листа SafetyList; |
| 68 | + |
| 69 | +* Создайте и запустите два потока, каждый из которых добавит 1000 элементов в созданный лист |
| 70 | + |
| 71 | +* После окончания работы потоков выведите на экран количество элементов в листе |
| 72 | + |
| 73 | +* Запустите приложение при помощи команды `make run` и проверьте количество элементов в листе. Так как мы запустили два потока, каждый из которых добавляет 1000 элементов, итоговое количество элементов должно быть равно 2000. |
| 74 | + |
| 75 | +* Попробуйте убрать синхронизацию из метода `add()` нашего листа. Прежде чем запустить программу, попробуйте ответить на вопрос: сколько элементов будет в листе после окончания работы потоков? |
| 76 | + |
| 77 | +* Запустите приложение несколько раз и изучите получившееся количество элементов. Количество элементов в листе в этом случае нельзя предугадать заранее, но практически наверняка каждый раз оно будет меньше 2000. Как думаете, почему так происходит? |
| 78 | + |
| 79 | +* Перед запуском тестов не забудьте вернуть синхронизацию в метод `add()` нашей реализации листа |
| 80 | + |
| 81 | +### Подсказки |
| 82 | + |
| 83 | +* При реализации метода `add()` листа, вам может пригодиться эта [статья](https://habr.com/ru/post/128269/) |
0 commit comments