потребитель производителя синхронизации назначений Java - PullRequest
0 голосов
/ 04 июля 2018

Я написал многопоточный код для проблемы потребителя производителя, в котором я написал синхронизированный блок внутри метода run потока потребителя и производителя, который блокирует общий список (я предположил) Таким образом, вопрос в том, будет ли блокировка в списке, потому что в каждом потоке будет свой синхронизированный блок, но они совместно используют один и тот же экземпляр списка

public class Main {
    static boolean finishFlag=false;
    final int queueSize = 20;
    List<Integer> queue = new LinkedList<>();
    Semaphore semaphoreForList = new Semaphore(queueSize);

    public Main(int producerCount,int consumerCount) {
        while(producerCount!=0) {
            new MyProducer(queue,semaphoreForList,queueSize).start(); //produces the producer
            producerCount--;
        }
        while(consumerCount!=0) {
            new MyConsumer(queue,semaphoreForList,queueSize).start(); //produces the consumer
            consumerCount--;
        }
    }

    public static void main(String args[]) {
        /*
         * input is from command line 1st i/p is number of producer and 2nd i/p is number of consumer
         */
        try {
            Main newMain = new Main(Integer.parseInt(args[0]),Integer.parseInt(args[1]));
            try {
                Thread.sleep(30000);
            }
            catch(InterruptedException e) {
            }
            System.out.println("exit");
            finishFlag=true;
        }
        catch(NumberFormatException e) {
            System.out.println(e.getMessage());
        }

    }
}

class MyProducer extends Thread{
    private List<Integer> queue;
    Semaphore semaphoreForList;
    int queueSize;
    public MyProducer(List<Integer> queue, Semaphore semaphoreForList,int queueSize) {
        this.queue = queue;
        this.semaphoreForList = semaphoreForList;
        this.queueSize = queueSize;
    }
    public void run() {
        while(!Main.finishFlag) {
            try {
                Thread.sleep((int)(Math.random()*1000));
            }
            catch(InterruptedException e) {
            }
            try {
                if(semaphoreForList.availablePermits()==0) {//check if any space is left on queue to put the int
                        System.out.println("no more spaces left");
                }
                else {
                    synchronized(queue) {
                        semaphoreForList.acquire(); //acquire resource by putting int on the queue
                        int rand=(int)(Math.random()*10+1);
                        queue.add(rand);
                        System.out.println(rand+" was put on queue and now length is "+(queueSize-semaphoreForList.availablePermits()));        
                    }
                }
            }
            catch(InterruptedException m) {
                System.out.println(m);
            }
        }
    }   
}

public class MyConsumer extends Thread{
    private List<Integer> queue; //shared queue by consumer and producer
    Semaphore semaphoreForList;
    int queueSize;
    public MyConsumer(List<Integer> queue, Semaphore semaphoreForList,int queueSize) {
        this.queue = queue;
        this.semaphoreForList = semaphoreForList;
        this.queueSize = queueSize;
    }
    public void run() {
        while(!Main.finishFlag) {//runs until finish flag is set to false by main
            try {
                Thread.sleep((int)(Math.random()*1000));//sleeps for random amount of time
            }
            catch(InterruptedException e) {
            }
            if((20-semaphoreForList.availablePermits())==0) {//checking if any int can be pulled from queue
                System.out.println("no int on queue");
            }
            else {
                synchronized(queue) {
                    int input=queue.remove(0);//releases the resource(position in queue) by pulling the int out of the queue and computing factorial 
                    semaphoreForList.release();
                    int copyOfInput=input;
                    int fact=1;
                    while(copyOfInput!=0) {
                        fact = fact*copyOfInput;
                        copyOfInput--;
                    }
                    System.out.println(input+" was pulled out from queue and the computed factorial is "+fact+
                            " the remaining length of queue is "+(queueSize-semaphoreForList.availablePermits()));
                }   
            }       
        }
    }
}

Ответы [ 2 ]

0 голосов
/ 05 июля 2018

Да, мьютекс / монитор связан с экземпляром Java Object, который в этом случае является общим списком. Это означает, что все потоки блокируют один и тот же мьютекс (связанный с queue и синхронизируются через него.

Итак, хорошая часть: ваша программа на самом деле поточно-ориентирована.

Однако дополнительный семафор на самом деле не имеет большого смысла во многих отношениях:

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

Как уже упоминал AnDus, это, возможно, лучше решить с помощью методов wait и notify, которые действуют как условные переменные. Скорее всего, вам понадобится даже два, один для разблокировки производителей и один для разблокирования потребителей.

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

0 голосов
/ 04 июля 2018

Я бы скорее рекомендовал использовать методы java.lang.Object wait() и notify() для создания алгоритма потребитель-производитель. При таком подходе очередь не будет блокироваться бесконечно повторяющимися и ненужными synchronized утверждениями, которые я считаю более производительным и «управляемым событиями» решением.

Эта ссылка может быть полезной - https://www.geeksforgeeks.org/producer-consumer-solution-using-threads-java/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...