Producer - consumer model of learning

  Producer - consumer model is a common structure, is a typical multi-threaded application scenarios. In this mode, Producers into the warehouse, consumer product consumption taken from the warehouse in order to ensure correct operation of the warehouse must be synchronized. Therefore, to use some of the blocking method. Consumers and producers during their operation on the warehouse, the warehouse needs to acquire the lock, otherwise it will be blocked; conversely, after the completion of the operation of the warehouse, the warehouse to release the lock, notification object blocked.

  Also worth noting is used here while (condition) + wait way to achieve a spin lock.

The first way:

  And a method of using wait notifyAll Object class. In this method, consumers are informed of inventory is zero, the method blocks waiting for call wait; the producers know inventory reaches a maximum, also call the wait method blocks waiting for. After the end of the operation of the warehouse, inventory must be suitable for the other party to the next step, so calling notifyAll method of notification object to be blocked. But there is a problem is that the original logical thing is i should inform producers consumer operation is completed, and after the completion of the producer shall inform the consumer, but wait-notifyAll can not do this level of granularity of control, only to inform all blocking objects, whether i consumers or producers, so it may cause unnecessary obstruction out of the queue. Of course, this can be resolved with a combination of Lock-Condition.

public class Producer extends Thread {

    private Queue<Integer> queue;
    private Random random = new Random();
    private int max;

    public Producer(Queue<Integer> queue, int max){
        this.queue = queue;
        this.max = max;
    }

    public void produce(){
        while (true){
            synchronized (queue){
                /***
                 * while (condition){
                 *      Object.wait();
                 * }
                 * --- self-rotation lock
                 */
                while (queue.size() >= max){
                    try {
                        System.out.println("The queue is full now!");
                        queue.wait();
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                }
                queue.add(queue.size());
                System.out.println(Thread.currentThread() + " successfully add one integer!");
                queue.notifyAll();

                try {
                    Thread.sleep(random.nextInt(10));
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public void run() {
        super.run();
        produce();
    }
}

public class Consumer extends Thread{

private Queue<Integer> queue;
private Random random = new Random();
public Consumer(Queue<Integer> queue){
this.queue = queue;
}
public void consume(){
while (true){
synchronized (queue){
while (queue.isEmpty()){
try {
System.out.println("The queue is empty now!");
queue.wait();
}catch (InterruptedException e){
e.printStackTrace();
}
}
queue.poll();
System.out.println(Thread.currentThread() + " remove one from the inventory.");
queue.notifyAll();

try {
Thread.sleep(random.nextInt(10));
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}

@Override
public void run() {
super.run();
consume();
}
}
 
 
public class Demo {

public static void main(String[] args) {
Queue<Integer> queue = new LinkedList<>();
Consumer consumer = new Consumer(queue), consumer1 = new Consumer(queue),
consumer2 = new Consumer(queue);
Producer producer = new Producer(queue, 10), producer1 = new Producer(queue, 10),
producer2 = new Producer(queue, 10), producer3 = new Producer(queue, 10);

consumer.start();
consumer1.start();
consumer2.start();

producer.start();
producer1.start();
producer2.start();
producer3.start();

try {
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
System.exit(0);
}

}
 

 

The second way:

  Lock-Condition combination of conditions in this way can notify the unblocking into two --full / empty. Such congestion control may be achieved in a smaller size, to avoid unnecessary operation.

public class ConsumerAndProducerLock {

    private static final ReentrantLock Lock = new ReentrantLock();
    private static final Condition fullCondition = Lock.newCondition();
    private static final Condition emptyCondition = Lock.newCondition();


    public static void main(String[] args) {
        Queue<Integer> queue = new LinkedList<>();
        queue.add(0);

        new Consumer(queue, "C1").start();
        new Producer(queue, "P1", 10).start();

        new Consumer(queue, "C2").start();
        new Producer(queue, "p2", 10).start();

        new Consumer(queue, "C3").start();
        new Producer(queue, "P3", 10).start();

        new Consumer(queue, "C4").start();
        new Producer(queue, "p4", 10).start();

        try {
            Thread.sleep(1000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        System.exit(0);
    }

    private static class Consumer extends Thread{

        private Queue<Integer> queue;
        private String name;

        public Consumer(Queue<Integer> queue, String name){
            this.queue = queue;
            this.name = name;
        }

        public void consume(){
            while (true){
                Lock.lock();
                while (queue.isEmpty()){
                    try {
                        System.out.println(name + " found the queue is empty");
                        emptyCondition.await();
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                }

                System.out.println("Consumer " + name + " consumes " + queue.poll());
                fullCondition.signalAll();

                Lock.unlock();
            }
        }

        @Override
        public void run() {
            super.run();
            consume();
        }
    }

    private static class Producer extends Thread{

        private Queue<Integer>  queue;
        private String  name;
        private int max;

        public Producer(Queue<Integer> queue, String name, int max){
            this.queue = queue;
            this.name = name;
            this.max =max;
        }

        public void produce(){
            while (true){
                Lock.lock();
                while (queue.size() >= max){
                    try {
                        System.out.println(name + " found the queue is full");
                        fullCondition.await();
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                }

                System.out.println("Producer " + name + " produces " + queue.size());
                queue.add(queue.size() + 1);

                emptyCondition.signalAll();
                Lock.unlock();
            }
        }

        @Override
        public void run() {
            super.run();
            produce();
        }
    }

}

Guess you like

Origin www.cnblogs.com/wenmingCode/p/12143808.html