简体   繁体   English

如何确保每个单独的线程仅运行一次代码?

[英]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. 我有几个同时运行的线程,每当每个线程启动时,我都希望每个人都从String Arraylist中获得一项,并坚持执行该特定的唯一项,直到完成为止。 What would be a good way to implement this? 什么是实现此目标的好方法? In the run method in a thread, I though about String uniqueItem = itemList.get(k); 在线程的run方法中,我虽然是关于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. 和k ++获取之后,但线程将一遍又一遍地运行该特定行,并且下次再次运行该行时,它将保留一个不同的唯一项。 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
    }
}

You should use a java.util.concurrent.BlockingQueue instead, as ArrayList is not thread safe. 您应该改用java.util.concurrent.BlockingQueue ,因为ArrayList不是线程安全的。

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

You want to avoid the scenario where two threads execute the get() at the same time then increment k at the same time. 您要避免两个线程同时执行get()然后同时增加k的情况。 To achieve that, you have to ensure k is incremented atomically by each thread. 为此,您必须确保每个线程自动增加k。 You can use AtomicInteger to do just that. 您可以使用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...
    }
}

You are using ExecutorService . 您正在使用ExecutorService This means that you do not need to pass thread instance, but a Runnable would suffice. 这意味着您不需要传递thread实例,但是Runnable就足够了。

Having said that, you will be creating Runnable instances, and passing them to the ExecutorService in some kind of loop. 话虽如此,您将创建Runnable实例,并将它们以某种循环的形式传递给ExecutorService 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. 您可以在本地字段中维护每个Runnable的状态,您可以在其中存储运行Runnable实例的索引。

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. 如果状态已经设置,则什么也不做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM