O M
O M

Reputation: 55

How do I make sure a line of code runs only once for each individual thread?

I have a few threads running simultaneously, and whenever each starts, I would like each individual to get one item from the String Arraylist, and hold onto that particular unique item until it completes. What would be a good way to implement this? In the run method in a thread, I though about String uniqueItem = itemList.get(k); and k++ after getting it, but the thread will run that particular line over and over, and the next time it runs it again, it will be holding onto a different unique item. Is there a way to make each thread get one item only once, and the next gets what's available, and so on, and hold onto that one item.

  ItemHolder thread = new ItemHolder();
    private ArrayList<String> itemList = new ArrayList<String>(); //Contains 4 Strings (e.g. Apple,     Orange, Watermelon, Pear)
    int k = 0;

    ExecutorService executor = Executors.newFixedThreadPool(4); //E.g. run 4 Threads
    executor.execute(thread);

    class ItemHolder extends Thread{
        public void run(){
            String uniqueItem = itemList.get(k); //Would like the first thread to grab the first index item, 0, and hold onto it until it finishes. But other thread that runs the same, I would like it to have index item, 1, and hold onto that, and the other thread to have whatever is available and so on.
            k++; //This would be a problem
    }
}

Upvotes: 0

Views: 571

Answers (3)

Tarik
Tarik

Reputation: 11209

You want to avoid the scenario where two threads execute the get() at the same time then increment k at the same time. To achieve that, you have to ensure k is incremented atomically by each thread. You can use AtomicInteger to do just that.

private ArrayList<String> itemList = new ArrayList<String>();
AtomicInteger a = new AtomicInteger();

ExecutorService executor = Executors.newFixedThreadPool(4);
for (int i=0; i<itemList.size(); i++) { // I assume itemList will not be modified
    ItemHolder thread = new ItemHolder();
    executor.execute(thread);
}

class ItemHolder extends Thread{
    public void run(){
        int k = a.getAndAdd(1);
        String uniqueItem = itemList.get(k);
        // Some lengthy processing might occur here...
    }
}

Upvotes: 0

ericson
ericson

Reputation: 1658

You should use a java.util.concurrent.BlockingQueue instead, as ArrayList is not thread safe.

Example code:

public class ItemHolderDemo {
    public static void main(String[] args) {
        BlockingQueue<String> queue = new LinkedBlockingQueue<>();
        queue.add("a");
        queue.add("b");

        Runnable thread = new ItemHolder(queue);
        ExecutorService executor = Executors.newFixedThreadPool(4); //E.g. run 4 Threads
        executor.execute(thread);

    }


    static class ItemHolder extends Thread {
        BlockingQueue<String> queue;

        public ItemHolder(BlockingQueue<String> queue) {
            this.queue = queue;
        }

        public void run() {
            String uniqueItem = null;
            // use while loop in case there is an interruption
            while (uniqueItem == null) {
                try {
                    // use queue.poll() with break statements if you want a timed wait
                    uniqueItem = queue.take();
                } catch (InterruptedException e) {
                }
            }
            // got item
            System.out.println(uniqueItem);
        }
    }
}

Upvotes: 1

Manish Maheshwari
Manish Maheshwari

Reputation: 4134

You are using ExecutorService. This means that you do not need to pass thread instance, but a Runnable would suffice.

Having said that, you will be creating Runnable instances, and passing them to the ExecutorService in some kind of loop. You can maintain the state of each Runnable in a local field, where you can store the index on which that Runnable instance is operating on.

You would check, if your runnable's state is not set, then set it to the element that the Runnable would operate upon. If the state is already set, then do nothing.

Upvotes: 0

Related Questions