0

As mentioned by Java_author:

5.1.1. Problems with Synchronized Collections

The synchronized collections are thread-safe, but you may sometimes need to use additional client-side locking to guard compound actions.


Example - Multiple producer/consumer problem:

Algorithm using busy wait approach for multiple producers consumers working on thread-unsafe buffer, requires,

global RingBuffer queue; // A thread-unsafe ring-buffer of tasks.

global Lock queueLock; // A mutex for the ring-buffer of tasks.


But below code runs busy wait(while(true){..}) algorithm using thread safe buffer(queue), without a lock,

/* NumbersProducer.java */
package responsive.blocking.prodcons;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadLocalRandom;

public class NumbersProducer implements Runnable{

    private BlockingQueue<Integer> numbersQueue;
    private final int poisonPill;
    private final int poisonPillPerProducer;
    
    public NumbersProducer(BlockingQueue<Integer> numbersQueue, int poisonPill, int poisonPillPerProducer) {
        this.numbersQueue = numbersQueue;
        this.poisonPill = poisonPill;
        this.poisonPillPerProducer = poisonPillPerProducer;
    }
    
    @Override
    public void run() {
        try {
            generateNumbers();
        }catch(InterruptedException e) {
            Thread.currentThread().interrupt();
            }
        
    }
    
    private void generateNumbers() throws InterruptedException{
        for(int i=0; i < 100; i++) {
            numbersQueue.put(ThreadLocalRandom.current().nextInt(100));
        }
        for(int j=0; j < poisonPillPerProducer; j++) {
            numbersQueue.put(poisonPill);
        }
    }
}

/* NumbersConsumer.java */
package responsive.blocking.prodcons;

import java.util.concurrent.BlockingQueue;

public class NumbersConsumer implements Runnable{
    
    private BlockingQueue<Integer> queue;
    private final int poisonPill;
    
    public NumbersConsumer(BlockingQueue<Integer> queue, int poisonPill) {
        this.queue = queue;
        this.poisonPill = poisonPill;
    }
    
    public void run() {
        try {
            while(true) {
                Integer number = queue.take();
                if(number.equals(poisonPill)) {
                    return;
                }
                System.out.println(Thread.currentThread().getName() + " result: " + number);
            }
        }catch(InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

/* Driver.java */
package responsive.blocking.prodcons;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class Driver {

    public static void main(String[] args) {
        int BOUND = 10;
        int nProducers = 4;
        int nConsumers = Runtime.getRuntime().availableProcessors();
        int poisonPill = Integer.MAX_VALUE;
        int value = 1;
        int poisonPillPerProducer = ((value = nConsumers / nProducers) < 1)?1:value;
        
        BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(BOUND);
        
        for(int i =0; i< nProducers; i++) {
            new Thread(new NumbersProducer(queue, poisonPill, poisonPillPerProducer)).start();
        }
        
        for(int j=0;j < nConsumers; j++ ) {
            new Thread(new NumbersConsumer(queue, poisonPill)).start();
        }
    }

}

Question:

In the above code,

How do I assess the need of additional client-side locking? Key is compound actions...

Community
  • 1
  • 1
overexchange
  • 15,768
  • 30
  • 152
  • 347
  • There are no compound actions, so no need for additional locking. – shmosel Oct 16 '17 at 02:06
  • @Oleg Yes, am wrong in saying that consumer is busy waiting, thread is actually sleeping on empty `queue`. I realized it after your comment. Does `put()` also make the producer thread sleep, when it says: *inserts the specified element into a queue, waiting for a free slot if necessary*? – overexchange Oct 16 '17 at 03:19
  • @chrylis After reading Oleg comment, I have realized wrong understanding in my query. Code in query following this [algorithm](https://en.wikipedia.org/wiki/Monitor_(synchronization)#Solving_the_bounded_producer/consumer_problem) without busy wait, where client code(`Driver`) is relying on thread safety delegation from `LinkedBlockingQueue` that should have 1 lock and two condition variables, within its implementation – overexchange Oct 16 '17 at 03:31

0 Answers0