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