java分配同步生产者使用者

时间:2018-07-04 17:36:05

标签: java multithreading concurrency producer-consumer

我针对生产者消费者问题编写了多线程代码,其中我在消费者和生产者线程的运行方法中编写了同步块,该块锁定了共享列表(我假设) 因此,问题在于,列表上是否会有锁定,因为每个线程都有自己的同步块,但是它们共享同一个列表实例

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 :(得分:0)

我宁愿建议使用java.lang.Object方法wait()notify()来创建消费者生产者算法。使用这种方法,队列不会被无休止的重复和不必要的synchronized语句阻塞,我认为这是一种性能更高且“事件驱动”的解决方案。

此链接可能会有所帮助- https://www.geeksforgeeks.org/producer-consumer-solution-using-threads-java/

答案 1 :(得分:0)

是的,互斥体/监视器与Java Object实例相关联,该实例是此实例中的共享列表。这意味着所有线程都锁定相同的互斥锁(与queue关联,并通过该互斥锁进行同步。

因此,好的一面是:您的程序实际上是线程安全的。

但是,实际上,附加信号量在各种方面并没有多大意义:

  • 检查(例如对availablePermits的检查)发生在锁之外,因此仅是关于队列状态的最佳猜测。此后不久可能会有所不同。
  • 试图在锁中获取信号量(只能在相同的锁中释放),似乎可以确保死锁。

正如AnDus所提到的,这可以通过使用充当条件变量的wait和notify方法来更好地解决。您很可能甚至需要两个,一个用于解除生产者的封锁,另一个用于解除消费者的封锁。

通常,如果这不是编码工作,请使用已经实现所需功能的类。在这种情况下,java.util.concurrent.BlockingQueue似乎就是您想要的。