Классы–синхронизаторы. Семафоры

Автор: Пользователь скрыл имя, 22 Января 2013 в 07:25, контрольная работа

Описание работы

В 1968 г. Э. Дейкстра предложил удобную форму механизма захвата/освобождения ресурсов, или, иными словами, механизм для синхронизации поведения процессов, который назвал семафор.
Семафоры (Semaphore) организуют взаимодействие потоков на основе набора разрешений. Они подобны взаимному исключению.

Работа содержит 1 файл

Laboratornaja_6.doc

— 45.00 Кб (Скачать)

Лабораторная работа

Классы–синхронизаторы. Семафоры

В 1968 г. Э. Дейкстра предложил удобную форму механизма  захвата/освобождения ресурсов, или, иными  словами, механизм для синхронизации  поведения процессов, который назвал семафор. 

Семафоры (Semaphore) организуют взаимодействие потоков на основе набора разрешений. Они  подобны взаимному исключению. Разница между ними в том, что семафор может управлять количеством потоков, которые имеют к нему доступ. Семафор устанавливается на предельное число потоков, которым доступ разрешен. Когда это число достигнуто, последующие потоки будут приостановлены, пока один или более потоков не отсоединятся от семафора и не освободят доступ.

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

Для выполнения операций с семафорами в Java-классе java.util.concurrent.Semaphore существуют специальные методы: acquire(), tryAcquire(), release().

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

Потоки могут не только пытаться пройти семафор, но и выдавать другим потокам разрешения. Для этого вызывается метод release(). Любой поток может выдать любое количество разрешений в пределах максимально допустимого для семафора.

Семафор со счетчиком разрешений равным 1 можно использовать в качестве затвора, который открывается и закрывается другим потоком.

Следует отметить, что у Семафора может быть различной сама стратегия  получения освободившегося ресурса.

 

 

Цель работы: Познакомиться с возможностями появившихся в пакете java.util.concurrent классов–синхронизаторов. В данной лабораторной работе рассматривается класс Semaphore.

  1. Рассмотрим еще один вариант решения задачи о читателях и писателях. В этом приложении обмен информацией между читателями и писателями осуществляется через циклический массив заданного размера. В качестве механизма синхронизации используются семафоры.

Один из семафоров управляет  писателями, он рассчитан на количество разрешений, равное размеру массива. В дальнейшем, разрешения будут выдавать читатели, после прочтения информации из массива.

Второй семафор управляет читателями. Он рассчитан на одно разрешение. После, того как писатель помещает данные в массив, он выдает очередное разрешение для семафора читателей.

Класс, который организует хранилище  данных в виде массива, выглядит так:

import java.util.concurrent.*;

 

class SmartQ {

    private ArrayBlockingQueue<Integer> impl;

    private Semaphore sWrite;

    private Semaphore sRead;

    public SmartQ(int n) {

        sWrite = new Semaphore(n);

        sRead = new Semaphore(1);

        impl = new ArrayBlockingQueue (n);

   try{

//семафор  сразу имеет разрешение, заберем  его, чтобы читатель не 

//смог  воспользоваться им раньше, чем  писатель запишет хотя бы

//одно значение

        sRead.acquire();

        } catch(InterruptedException e){};

    }

    public void push(int i) throws InterruptedException {

        sWrite.acquire();//запрос разрешения на запись

        synchronized(impl) {

            impl.put(i);

            sRead.release();//выдано разрешение на чтение

        }

    }

    public int pop() throws InterruptedException {

        sRead.acquire();//запрос разрешения на чтение

        synchronized(impl) {

            int tmp = impl.poll();

            sWrite.release();//выдано разрешение на запись.

            return tmp;

        }

       

    }

Классы писателя и читателя выглядят следующим образом:

class Reader implements Runnable {

    private SmartQ q;

    private String name;//для отладки

    private int readTime;

    private boolean stopFlag;

    public Reader(String name, SmartQ q, int readTime) {

        this.name = name;

        this.q = q;

        this.readTime = readTime;

        stopFlag = false;

    }

    public void stop() { stopFlag = true; }

    public void run() {

        try {

            while (!stopFlag) {

                System.out.println("   "+name+

"       get ="+q.pop() );

                Thread.sleep(readTime);

            }

        } catch(Exception e) {}

    }

class Writer implements Runnable {

    private SmartQ q;

    private int writeTime;

    private boolean stopFlag;

    private int base, step;

    public Writer(SmartQ q, int writeTime, int base, int step) {

        this.q = q;

        this.writeTime = writeTime;

        stopFlag = false;

        this.base = base;

        this.step = step;

    }

    public void stop() { stopFlag = true; }

    public void run() {

        try {

            int i = base;

            while (!stopFlag) {

               System.out.println("put="+i);

                q.push(i);

                i += step;

                Thread.sleep(writeTime);

            }

        } catch(Exception e) {}

}}

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

import java.util.*;

public class Semafor {

    static final int nWriters = 10;

    public static void main(String[] args) {

        SmartQ q = new SmartQ(10);

        List<Reader> listR = new ArrayList<Reader>();

        List<Writer> listW = new ArrayList<Writer>();

        for ( int i = 0;  i < nWriters;  ++i) {

            Reader r = new Reader("#"+i,q, 10);

            new Thread(r).start();

            listR.add(r);

            Writer w = new Writer(q, 10, i, nWriters);

            new Thread(w).start();

            listW.add(w);

        }

        try{

            Thread.sleep(100);

        } catch(Exception e) {}

        for(Reader r : listR) {

            r.stop();

        }

        for(Writer w : listW) {

            w.stop();

        }

    }

}

Упражнения.

  1. Проведите эксперименты с семафорами. Попробуйте изменить количество допустимых разрешений у семафора для читателей. Что произойдет? И у семафора для писателей.

При создании семафоров читателей  и писателей:

sRead = new Semaphore(1);

sWrite = new Semaphore(n);

количество  допустимых разрешений соответственно было равно 1 и n. Изменив количество разрешений у читателей, например, на n, тем самым получим, что сразу n читателей могут получить доступ к хранилищу, куда писатель что-то записал. И наоборот, если количество допустимых разрешений у писателей возьмем равным 1, то записать данных в хранилище может только один писатель, остальные ожидают разрешение на запись (sWrite.acquire()).

       

 

  1. Измените время засыпания потоков, как это отразится на работе всего приложения.

Если в самом классе Semafor изменить время засыпания потока (например, увеличить), в данном случае:

                Thread.sleep(100);

делаем     Thread.sleep(500);

то  все потоки сработают большее  число раз, чем в предыдущем случае.

  1. Введенное в классе Reader имя позволяет следить, кто из читателей выполняет операцию. Добавьте аналогичную возможность для класса Writer.

          Добавляем  возможность следить за тем,  кто из писателей записывает

информацию в хранилище:

class Writer implements Runnable {

    private SmartQ q;

    private int writeTime;

    private String name;

    private boolean stopFlag;

    private int base, step;

    public Writer(SmartQ q, int writeTime, int base, int step,String name) {

        this.q = q;

        this.writeTime = writeTime;

        stopFlag = false;

        this.base = base;

        this.step = step;

        this.name=name;

    }    public void stop() { stopFlag = true; }

    public void run() {

        try {

            int i = base;

            while (!stopFlag) {

               System.out.println("writer   "+name+"   push  ="+i);

                q.push(i);

                i += step;

                Thread.sleep(writeTime);

            }

        } catch(Exception e) {}

}}

Теперь можно следить за тем, кто из писателей записывает и кто из читателей читает.


Информация о работе Классы–синхронизаторы. Семафоры