<file_sep>import java.util.Random;

public enum BaseColor {
        Red,
        Green,
        Black,
        Orange,
        White,
        Purple,
        Haze,
        Nutella,
        Banana,
        Ice,
        Mat,
        XYZ,
        Space,
        A41,
        B56,
        C8585,
        D90,
        Zwart,
        Groy,
        Pop,
        Blue;

        /**
         * Pick a random value of the BaseColor enum.
         * @return a random BaseColor.
         */
        public static BaseColor getRandomColor() {
            Random random = new Random();
            return values()[random.nextInt(values().length)];           
        }
    }<file_sep>import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;

import com.google.common.util.concurrent.Striped;

public class App {

    static ExecutorService service = Executors.newFixedThreadPool(100);
    static final int SIZE = 10;
    static final int LOOP = 100;
    static final int TASK_COUNT = 1000;
    static List<Bag> bags = new ArrayList<>();
    static final Object mtx = new Object();
    static Striped<Lock> stripedLocks = Striped.lock(SIZE);  // total number of Locks

    public static void main(String[] args) {
        populateBags();    

        distribute();

        dispose();        

        checkBagsForRaceCondition();
    }

    static void checkBagsForRaceCondition() {
        for (Bag bag : bags) {           
            if(bag.getColors().size() > BaseColor.values().length) {
                 System.out.println(bag.toString());                    
            }   
        }
    }

    static void distribute() {
       
        for(int j = 0; j < LOOP; j++) {
            System.out.println("Tasking...");
            for (int i = 0; i < TASK_COUNT; i++) {
                service.submit(new Runnable() {
                    @Override
                    public void run() {
                        int index = (int) (Math.random() * SIZE);              
                        BaseColor color = BaseColor.getRandomColor();                        
                        Bag bag = bags.get(index);

                        // Better memory footprints compared to creating a new lock per runnable, good throughput
                        Lock lock = stripedLocks.get(bag.getIndex());
                        lock.lock();
                        if (!bag.containsItem(color)) {
                            bag.addItem(new Item(color));
                        }
                        lock.unlock();
                    
                        /* One lock for all runnables -> bad throughput, less efficient
                        synchronized(mtx) {
                            if (!bag.containsItem(color)) {
                                bag.addItem(new Item(color));
                            }
                        }
                        */
                    }
                });
            }  
        }         
    }

    static void dispose() {
        System.out.println("Shutting down...");
        try {
            service.shutdown();
            if (!service.awaitTermination(10000, TimeUnit.MILLISECONDS)) {
                System.out.println("Shutting down with awating...");
                service.shutdownNow();
            } 
        } catch (InterruptedException e) {
                System.out.println("Shutting down with exception...");
                service.shutdownNow();
        }
    }

    static void populateBags() {
        bags.clear();
        System.out.println("Populating bags...");
        for (int i = 0; i < SIZE; i++) {
            bags.add(new Bag(i));
        }
    }
}
<file_sep># StripedLock Usage
Sample usage of Striped lock's from Guava library.