如何确保每个线程只运行一行代码?

时间:2014-11-17 04:55:09

标签: java multithreading threadpool executorservice

我有几个线程同时运行,每当每个线程开始时,我希望每个人从String Arraylist中获取一个项目,并保持该特定的唯一项目,直到它完成。实现这个的好方法是什么?在一个线程的run方法中,我虽然关于String uniqueItem = itemList.get(k);在获得它之后获得k ++,但是线程会一遍又一遍地运行该特定行,并且下次再次运行它时,它将保持不同的唯一项。有没有办法让每个线程只获得一个项目,然后下一个获得可用的内容,依此类推,并保留该项目。

  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
    }
}

3 个答案:

答案 0 :(得分:1)

您应该使用java.util.concurrent.BlockingQueue,因为ArrayList不是线程安全的。

示例代码:

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);
        }
    }
}

答案 1 :(得分:0)

您希望避免两个线程同时执行get()然后同时增加k的情况。要实现这一点,您必须确保每个线程以原子方式递增k。您可以使用AtomicInteger来做到这一点。

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...
    }
}

答案 2 :(得分:0)

您正在使用ExecutorService。这意味着您不需要传递thread实例,但Runnable就足够了。

话虽如此,您将创建Runnable个实例,并在某种循环中将它们传递给ExecutorService。您可以在本地字段中维护每个Runnable的状态,您可以在其中存储运行Runnable实例的索引。

如果未设置runnable的状态,则检查,然后将其设置为Runnable将运行的元素。如果状态已经设置,则不执行任何操作。