简体   繁体   中英

Passing a work item between threads (Java)

I have two threads. The producer is producing pieces of data (String objects), where the consumer processes these strings. The catch is that my application only needs the most recent data object to be processed. In other words, if the producer managed to produce two strings "s1" and then "s2" then I want the consumer to process only "s2". "s1" can be safely discarded.

Of course there's no problem implementing a class that realizes this behavior, but I want to use a standard mechanism from java.util.concurrent (if such a mechanism exists). Note that SynchronousQueue is not a good solution: the consumer will block when enqueueing "s1" and will not get the chance to produce "s2".

(In short, I am looking for a single-element collection with a blocking remove operation and a non-blocking set operation)

Any ideas?

I think your best answer is probably to use ArrayBlockingQueue, where the producer (you only have one producer, right?) removes any existing element before adding the new element.

Sure, there are race conditions in this implementation: the consumer could start processing an element just before the producer removes it. But those race conditions will always exist, no matter what data structure you use.

What about the Exchanger class? This is the standard way of exchanging objects between threads. Specialize it with your class, may be a list of strings. Make the consumer only use the first/last one.

You could use an array of size one for that:

String[] oeq = new String[1];

Sample source:

public class Test {
    private static final String[] oeq = new String[1];
    public static void main(String[] args) {
        (new Producer()).start();
        (new Consumer()).start();
        (new Consumer()).start();
        (new Consumer()).start();
        (new Consumer()).start();
        (new Consumer()).start();
        (new Consumer()).start();
    }

    private static class Producer extends Thread {
        public void run() {
            int i=0;
            while(true) {
                i++;
                synchronized(oeq) {
                    oeq[0] = ""+i;
                    oeq.notifyAll();
                }
            }
        }
    }

    private static class Consumer extends Thread {
        public void run() {
            String workload = null;
            while(true) {
                synchronized(oeq) {
                    try {
                        oeq.wait();
                    } catch(InterruptedException ie) {
                        ie.printStackTrace();
                    }
                    if(oeq[0] != null) {
                        workload = oeq[0];
                        oeq[0] = null;
                    }
                }
                if(workload != null) {
                    System.out.println(workload);
                }
            }
        }
    }
}

Well, if you only want the most recently produced string, then you don't need a queue at all - all you need is a string reference: the producer sets it, the consumer reads it. If the consumer takes so long to read it that the producer re-sets it ... so what?

Setting and reading references are atomic. The only issue is if you want the consumer to somehow be notified that there's a string available. But even then ... if the consumer is doing something that takes a while, then you really don't need any fancy-pants stuff from the concurrency libraries.

Note, btw, that this example works with any number of producer and/or consumer threads.

import java.util.Random;

public class Example {
    public static void main(String[] av) {
        new Example().go();
    }

    Object  mutex       = new Object();
    String  theString   = null;

    void go() {
        Runnable producer = new Runnable() {
            public void run() {
                Random rnd = new Random();
                try {
                    for (;;) {
                        Thread.sleep(rnd.nextInt(10000));
                        synchronized (mutex) {
                            theString = "" + System.currentTimeMillis();
                            System.out.println("Producer: Setting string to " + theString);
                            mutex.notify();
                        }
                    }
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            }
        };

        Runnable consumer = new Runnable() {
            public void run() {
                try {
                    String mostRecentValue = null;
                    Random rnd = new Random();
                    for (;;) {
                        synchronized (mutex) {
                            // we use == because the producer
                            // creates new string
                            // instances
                            if (theString == mostRecentValue) {
                                System.out.println("Consumer: Waiting for new value");
                                mutex.wait();
                                System.out.println("Consumer: Producer woke me up!");
                            } else {
                                System.out.println("Consumer: There's a new value waiting for me");
                            }
                            mostRecentValue = theString;
                        }
                        System.out.println("Consumer: processing " + mostRecentValue);
                        Thread.sleep(rnd.nextInt(10000));
                    }
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        };


        new Thread(producer).start();
        new Thread(consumer).start();
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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