Синхронизация потоков java семафоры

Синхронизация потоков java семафоры

В Java ключевое слово synchronized используется для обеспечения взаимного исключения и гарантирует, что только один поток может получить доступ к критической секции кода в данный момент. Ключевое слово synchronized может использоваться с блоком кода или методом, и оно использует монитор объекта для синхронизации. В Java монитор — это синхронизационный конструкт, который ассоциирован с объектом. Каждый объект в Java имеет встроенный монитор, который можно использовать для синхронизации доступа к методам и полям этого объекта. Когда поток входит в синхронизированный блок кода или метод, он получает монитор, связанный с объектом, и удерживает его до тех пор, пока не выйдет из блока кода или метода. Мьютекс — это синхронизационный примитив, который используется для защиты общих ресурсов от одновременного доступа нескольких потоков. В Java ключевое слово synchronized может использоваться для обеспечения взаимного исключения, что аналогично функциональности мьютекса. Семафор — это синхронизационный примитив, который используется для управления доступом к общему ресурсу. В Java класс Semaphore может использоваться для реализации семафоров, которые можно использовать для контроля доступа к общим ресурсам несколькими потоками. Таким образом, ключевое слово synchronized использует монитор объекта, который аналогичен мьютексу. Оно не использует семафор напрямую, но семафор можно реализовать с помощью класса Semaphore в Java.

Странно, что в «Философия Java» Брюса Эккеля (4 издание) дают определения мьютекса и монитора наоборот: мьютекс — это механизм блокировки, а монитор — флаг, который используется для того, чтобы показать, что ресурс заблокирован: > Для решения проблемы соперничества потоков фактически все многопоточные схемы синхронизируют доступ к разделяемьм ресурсам. Это означает, что доступ к разделяе­мому ресурсу в один момент времени может получить только одна задача. Чаще всего это выполняется помещением фрагмента кода в предложение блокировки так, что одновременно пройти по этому фрагменту кода может только одна задача. Поскольку такое предложение блокировки дает эффект взаимного исключения (mutual exclusion), этот механизм часто называют мьютексом (mutex). > Каждый объект содержит объект простой блокировки (также называемый монитором), который автоматически является частью этого объекта (вам не придется писать для нее специального кода). Когда вы вызываете любой синхронизированный (synchronized) метод, объект переходит в состояние блокировки, и пока этот метод не закончит свою работу и не снимет блокировку, другие синхронизированные методы для объекта не могут быть вызваны.

Читайте также:  Dynamic types in java

Написано хорошо, понятно, но мне кажется, в конце немного понятия перепутаны. В статье написано, что мьютекс — это одноместный семафор, но судя по всему предыдущему объяснению, одноместным семафором является не мьютекс, а монитор. А мьютекс — это понятие, сходное не с семафором, а с разрешениями, которые семафор выдает. То есть, у монитора — один мьютекс, Соответственно, работает с данным кодом в один момент времени не более 1 потока. У семафора N разрешений. Соответственно, работают с данным кодом в один момент времени не более N потоков.

Монитор — невидимый для программиста кусок кода исполняемый jvm. Ну как бы и в чём прикол? Ну типа есть много всякого скрытого кода связанного с ключевыми словами или с другими языками программирования, это очевидно вроде. Но почему именно этот код имеет отдельное название и целое объяснение-пояснение. Есть умные люди в чате?) Объясните please зачем это знать 🙏

Прочитал несколько источников и понял так: Synchronized — ключевое слово, указывающее что для потоков, работающих с этим объектом/блоком кода, будет применяться механизм управления потоками (монитор).

Объект, указанный в ( ) содержит в себе маркер и может иметь 2 состояния: закрыт/открыт. Когда поток доходит до синхронизированного объекта/кода, он обращается к маркеру и запрашивает состояние. Это состояние контролирует монитор. Т.е. маркеры переключает монитор, а запрос делает поток. > Монитор — механизм контроля потоков при работе с сихронизированным объектом. Есть 2 типа механизма (монитора): мьютекс и семафор. 1. Механизм мьютекса ограничивает доступ к объекту/коду до 1 потока, т.е. одновременно с объектом может работать 1 поток. 2. Механизм семафора ограничивает доступ до N-го количества потоков одновременно, т.е. можно задать количество потоков. Мьютекс используется по умолчанию, а для задействования семафора нужно инициализировать класс Semaphor. У семафора через объект Semaphor можно настраивать: — количество потоков, которые могут одновременно работать с объектом;

 Semaphore(int permits) // конструктор 

— очередность работы потоков с объектом: последовательно (первый пришел — первый приступил к работе) или управление полностью отдается планировщику.

 Semaphore(. boolean fair) // конструктор 

Источник

Читайте также:  Html meta http equiv javascript

Синхронизация потоков java семафоры

Семафоры представляют еще одно средство синхронизации для доступа к ресурсу. В Java семафоры представлены классом Semaphore , который располагается в пакете java.util.concurrent .

Для управления доступом к ресурсу семафор использует счетчик, представляющий количество разрешений. Если значение счетчика больше нуля, то поток получает доступ к ресурсу, при этом счетчик уменьшается на единицу. После окончания работы с ресурсом поток освобождает семафор, и счетчик увеличивается на единицу. Если же счетчик равен нулю, то поток блокируется и ждет, пока не получит разрешение от семафора.

Установить количество разрешений для доступа к ресурсу можно с помощью конструкторов класса Semaphore:

Semaphore(int permits) Semaphore(int permits, boolean fair)

Параметр permits указывает на количество допустимых разрешений для доступа к ресурсу. Параметр fair во втором конструкторе позволяет установить очередность получения доступа. Если он равен true , то разрешения будут предоставляться ожидающим потокам в том порядке, в каком они запрашивали доступ. Если же он равен false , то разрешения будут предоставляться в неопределенном порядке.

Для получения разрешения у семафора надо вызвать метод acquire() , который имеет две формы:

void acquire() throws InterruptedException void acquire(int permits) throws InterruptedException

Для получения одного разрешения применяется первый вариант, а для получения нескольких разрешений — второй вариант.

После вызова этого метода пока поток не получит разрешение, он блокируется.

После окончания работы с ресурсом полученное ранее разрешение надо освободить с помощью метода release() :

void release() void release(int permits)

Первый вариант метода освобождает одно разрешение, а второй вариант — количество разрешений, указанных в permits.

Используем семафор в простом примере:

import java.util.concurrent.Semaphore; public class Program < public static void main(String[] args) < Semaphore sem = new Semaphore(1); // 1 разрешение CommonResource res = new CommonResource(); new Thread(new CountThread(res, sem, "CountThread 1")).start(); new Thread(new CountThread(res, sem, "CountThread 2")).start(); new Thread(new CountThread(res, sem, "CountThread 3")).start(); >> class CommonResource < int x=0; >class CountThread implements Runnable < CommonResource res; Semaphore sem; String name; CountThread(CommonResource res, Semaphore sem, String name)< this.res=res; this.sem=sem; this.name=name; >public void run() < try< System.out.println(name + " ожидает разрешение"); sem.acquire(); res.x=1; for (int i = 1; i < 5; i++)< System.out.println(this.name + ": " + res.x); res.x++; Thread.sleep(100); >> catch(InterruptedException e) System.out.println(name + " освобождает разрешение"); sem.release(); > >

Итак, здесь есть общий ресурс CommonResource с полем x, которое изменяется каждым потоком. Потоки представлены классом CountThread, который получает семафор и выполняет некоторые действия над ресурсом. В основном классе программы эти потоки запускаются. В итоге мы получим следующий вывод:

CountThread 1 ожидает разрешение CountThread 2 ожидает разрешение CountThread 3 ожидает разрешение CountThread 1: 1 CountThread 1: 2 CountThread 1: 3 CountThread 1: 4 CountThread 1 освобождает разрешение CountThread 3: 1 CountThread 3: 2 CountThread 3: 3 CountThread 3: 4 CountThread 3 освобождает разрешение CountThread 2: 1 CountThread 2: 2 CountThread 2: 3 CountThread 2: 4 CountThread 2 освобождает разрешение

Семафоры отлично подходят для решения задач, где надо ограничивать доступ. Например, классическая задача про обедающих философов. Ее суть: есть несколько философов, допустим, пять, но одновременно за столом могут сидеть не более двух. И надо, чтобы все философы пообедали, но при этом не возникло взаимоблокировки философами друг друга в борьбе за тарелку и вилку:

import java.util.concurrent.Semaphore; public class Program < public static void main(String[] args) < Semaphore sem = new Semaphore(2); for(int i=1;i<6;i++) new Philosopher(sem,i).start(); >> // класс философа class Philosopher extends Thread < Semaphore sem; // семафор. ограничивающий число философов // кол-во приемов пищи int num = 0; // условный номер философа int id; // в качестве параметров конструктора передаем идентификатор философа и семафор Philosopher(Semaphore sem, int id) < this.sem=sem; this.id=id; >public void run() < try < while(num<3)// пока количество приемов пищи не достигнет 3 < //Запрашиваем у семафора разрешение на выполнение sem.acquire(); System.out.println ("Философ " + id+" садится за стол"); // философ ест sleep(500); num++; System.out.println ("Философ " + id+" выходит из-за стола"); sem.release(); // философ гуляет sleep(500); >> catch(InterruptedException e) < System.out.println ("у философа " + id + " проблемы со здоровьем"); >> >

В итоге только два философа смогут одновременно находиться за столом, а другие будут ждать:

Философ 1 садится за стол Философ 3 садится за стол Философ 3 выходит из-за стола Философ 1 выходит из-за стола Философ 2 садится за стол Философ 4 садится за стол Философ 2 выходит из-за стола Философ 4 выходит из-за стола Философ 5 садится за стол Философ 1 садится за стол Философ 1 выходит из-за стола Философ 5 выходит из-за стола Философ 3 садится за стол Философ 2 садится за стол Философ 3 выходит из-за стола Философ 4 садится за стол Философ 2 выходит из-за стола Философ 5 садится за стол Философ 4 выходит из-за стола Философ 5 выходит из-за стола Философ 1 садится за стол Философ 3 садится за стол Философ 1 выходит из-за стола Философ 2 садится за стол Философ 3 выходит из-за стола Философ 5 садится за стол Философ 2 выходит из-за стола Философ 4 садится за стол Философ 5 выходит из-за стола Философ 4 выходит из-за стола

Источник

Оцените статью