[Zatan] look at production - consumption patterns

Why is separated by a queue between producers and consumers?

First, producers and consumers due to inconsistencies in speed, so we need a space for the buffer. This can be decoupled from producers and consumers, producers, production data, when the data submitted to the hands of consumers do not need the job, as long as the data thrown into the buffer just fine. This allows each doing.

Why is a buffer queue?

Typically, this buffer data structure is an ordered queue. If the order is actually nothing to deal with the requirements, in fact, not have to use the queue. Interpolation can be.

Why when the buffer is accessed to acquire the lock?

This data buffer structure is multi-threaded concurrent access (producers, consumers thread), it is necessary to lock the one hand, to protect its structure is not destroyed, on the other hand to ensure the correctness of the code.

This is not to be used?

That can be used with, but performance may be poor.

Why poor performance?

Consider this scenario: the buffer is full. Producers will always try to drive a throw things, so we have "won lock - release the lock - get the lock - release the lock." On the one hand, producers idling, wasting CPU time slice, it will affect the scheduling of other threads. At this time, if a consumer has processed the data at hand, I want a chance to come out a deal, and that this time the producers and consumers would be unnecessary competition, because this time the producers grabbed the lock useless.

This, which can do ah?

Simple, two cases, one is when the buffer is full, throw things if producers try to fill it, put it hangs. Similarly, when the buffer is empty, if consumers try to fill it, and it hangs.

When will you wake it?

It is not the same as you, when the buffer to the data (from scratch), you wake up the consumer thread. When the buffer has a free space (from full to dissatisfaction), wakes producer thread.

That code is how to write it?

First we simply implement a "lock" is so below.

public  class Lock {
     / ** 
     * waiting thread lock queue 
     * / 
    Private List <the Thread> = waitThreads new new the ArrayList <> ();
     / ** 
     * guard 
     * / 
    Private of AtomicInteger Guard = new new of AtomicInteger (0 );
     / ** 
     * lock flag 
     * / 
    Private of AtomicInteger lockFlag = new new of AtomicInteger (0 );
     / ** 
     * current thread owner 
     * / 
    Private the thread Holder; 

    public  void lock () {
         IF (Objects.equals (Holder, Thread.currentThread ()))// If a thread lock has been obtained, the direct return 
            return ;
         the while (! Guard.compareAndSet (0, 1)) // try to get the guards allowed 
            ;
         IF (lockFlag.intValue () == 0 ) { 
            lockFlag.set ( 1) ; // lock marked as "occupied" 
            Holder = Thread.currentThread (); // lock owner is set to the current thread 
            guard.set (0); // release guard 
        } the else { 
            waitThreads.add (the thread .currentThread ()); // added to the waiting queue 
            guard.set (0); // release guard 
            LockSupport.park (); //The current thread is suspended 
            Holder Thread.currentThread = (); // when the thread resumes execution from the line, it shows this thread to acquire the lock 
        } 
    } 

    public  void UNLOCK () {
         IF (Objects.equals (Holder, the Thread! .currentThread ())) // if not the lock owner releases the lock no qualifications 
            return ;
         the while ! (guard.compareAndSet (0, 1 )) 
            ; 
        IF (waitThreads.size () == 0) { // determine whether threads are waiting 
            lockFlag.set (0); // If not, it will lock marked "free" 
            Holder = null ; 
            guard.set ( 0); // release guard
        } The else { 
            LockSupport.unpark (waitThreads.remove ( 0)); // if threads are waiting in the queue is a first wake-up 
            guard.set (0); // release guard 
        } 
    } 
}

Then, we come to realize what kind of buffer.

public  class buffercache {
     / ** 
     * buffer array for storing data 
     * / 
    Private Object [] Data;
     / ** 
     * index = Read> next to where to take the consumption data 
     * / 
    Private  int readIndex;
     / ** 
     * where write index => next to put the incoming data 
     * / 
    Private  int writeIndex;
     / ** 
     * number of current data in the buffer 
     * / 
    Private  int COUNT;
     / ** 
     * the producer thread wait queue 
     * / 
    Private List <the thread > = waitProducers new new the ArrayList <> ();
     / ** 
     * waiting queue consumer thread 
     * / 
    PrivateList <the Thread> = waitConsumers new new the ArrayList <> ();
     / ** 
     * lock previously implemented 
     * / 
    Private Lock Lock = new new Lock (); 

    public buffercache ( int Initial) {
         the this .data = new new Object [Initial]; 
    } 

    public  void PUT (Object E) { 
        Lock.lock (); // get lock 
        the while (COUNT == data.length) { // If full, the thread will suspend production 
            waitProducers.add (Thread.currentThread ()) ; // into the queue, so when you can wake up to find 
            lock.unlock (); //Lock release 
            LockSupport.park (); // suspends the current thread 
            Lock.lock (); // woke up again to acquire the lock 

        } 

        Data [writeIndex] = E;   // logging data 
        COUNT ++ ;
         IF (++ == data.length writeIndex) { // recycling storage 
            writeIndex = 0 ; 
        } 
        the while (waitConsumers.size () = 0) {! // wake-up thread consumption 
            LockSupport.unpark (waitConsumers.remove (0 )); 
        } 
        Lock .unlock (); // release lock 
    } 

    public Object Take () {//同理
        lock.lock();
        Object e = null;
        while (count == 0) {
            waitConsumers.add(Thread.currentThread());
            lock.unlock();
            LockSupport.park();
            lock.lock();
        }

        e = data[readIndex];
        count--;
        if(++readIndex == data.length) {
            readIndex = 0;
        }
        while(waitProducers.size() != 0) {
            LockSupport.unpark(waitProducers.remove(0));
        }
        lock.unlock();
        return e;
    }

    private static class Task1 implements Runnable { //生产任务
        private int num;
        private BufferCache cache;
        private String name;

        public Task1(BufferCache cache, String index) {
            this.name = "producer-" + index;
            this.num = 0;
            this.cache = cache;
        }

        @Override
        public voidRUN () { 
            String Data; 
            the while ( to true ) { // every second to throw a queue data 
                Data = NUM + "from" + name; 
                cache.put (Data); 
                System.out.println (name + "release into: "+ Data); 
                NUM ++ ;
                 the try { 
                    the Thread.sleep ( 1000 ); 
                } the catch (InterruptedException E) { 
                    e.printStackTrace (); 
                } 
            } 
        } 
    } 


    Private  static class Task2 the implements the Runnable {
         Private buffercache Cache; 

        public Task2 (buffercache Cache) {
             the this .cache = Cache; 
        } 

        @Override 
        public  void RUN () {
             the while ( to true ) { // continue to fetch data from the queue 
                Object E = Cache. Take (); 
                System.out.println ( "consumption to:" + E); 
            } 
        } 
    } 
    public  static  void main (String [] args) { // run cases
        BufferCache cache = new BufferCache(20);
        Thread producer;
        Thread consumer;
        for(int i = 0; i < 5; i++) { //开5个生产者
            producer = new Thread(new Task1(cache, i + ""));
            producer.start();
        }

        for(int i = 0; i < 3; i++) { //开3个消费者
            consumer = new Thread(new Task2(cache));
            consumer.start();
        }
    }
}

Why conditional use while loops, if not do it?

If the wake of the producer thread A, when it may resume execution, the buffer has been filled with the producer thread B again, so it needs to judge once again.

Why, when they would go to restore the thread to acquire the lock?

To lock is obtained during the determination and execution conditions will not change. So that the code is correct to implement. Then detailed point is, when A producer thread to acquire a lock, other threads can not change the status of the producer buffer (because the other producer thread if you want to change, it must first obtain a lock), to acquire the lock release thread A during the lock, it sees the state will not change.

These two seem to queue with the condition variable like this have anything to do with the condition variable?

In fact, this is the essence of condition variables, condition variable is a queue, when the conditions are not satisfied, put the thread into the queue; when the conditions are met, you can wake up one or more threads, let them continue.

You can refer to the JDK, a class that implements ArrayBlockingQueue BlockingQueue, and see if it is like with the above code.

Relations locks and condition variables

On the one hand, due to the condition variable is a queue, when multithreaded access, it must ensure that its thread-safe, so it is usually associated with a lock object. To access this queue, you must first obtain a lock.

On the other hand, when the conditional judgment is inseparable from the lock (guaranteed during the determination and execution conditions will not change)

So, condition variables, and is tied to a lock, the lock can not be separated or condition variable. It would appear, JDK in, Condition objects generated by the Lock objects very easy to understand.

Condition x = lock.newCondition();

 

Guess you like

Origin www.cnblogs.com/longfurcat/p/11494441.html