Hot questions for Running Guava in Multi-threading

Top 10 Java Open Source / Guava / Running in Multi-threading

Guava: How does Cacheloader.load() work

Question: Assume that I have two threads, Thread A and Thread B, and a LoadingCache<String, String> that is empty and has an expiration of 10 minutes. A CacheLoader was used to build the LoadingCache and all it does it retrieve from the database.

Assume that the LoadingCache is still empty and LoadingCache.get(key) was invoked by Thread A and Thread B simultaneously. Will the CacheLoader.load() method get called twice?

From what I've read in the docs: If another call to get(K) or getUnchecked(K) is currently loading the value for key, simply waits for that thread to finish and returns its loaded value. Note that multiple threads can concurrently load values for distinct keys.

To verify my understanding, if there is a 5ms difference between Thread A and Thread B, then Thread A will automatically lock the CacheLoader.load() method, loads the value, then Thread B just picks up the loaded value. With this, synchronization isn't necessary. Is this right?

Answer: No, load will not get called twice; one of them will win, and the same thing happens as in your second case, which is that the second thread waits until the first thread computes the value, and then picks up that value, no extra synchronization required.


Capturing executor for current thread

Question: I'm using ListenableFuture from Guava, and one nice thing about them is that one pass Executor to the Futures.addCallback method, that is, ask to execute the callback on a given thread/executor.

In my Android application, I want to be able to start the asynchronous execution based on ListenableFuture in the UI thread, and schedule a callback which is also executed also on the UI thread. Therefore, I'd like to somehow submit the UI thread executor to the Futures.addCallback method mentioned above. How to achieve that?

Or, in other words, I want to have an executor for the UI thread. Is it available already in Android, or, if I have to create my own, how do I do that?

Answer: I think I've see some implementation doing that. The basic Idea is roughly

class HandlerThreadExecutor implements Executor {
    private final Handler mHandler;
    public HandlerThreadExecutor(Handler optionalHandler) {
        mHandler = optionalHandler != null ? optionalHandler : new Handler(Looper.getMainLooper());
    }

    @Override
    public void execute(Runnable command) {
        mHandler.post(command);
    }
}

You can delegate to run anything in the main thread by passing it to a handler for the main thread.

The advantage over using the current thread's looper is that it makes it explicit which Looper you use. In your solution you take the Looper of whatever thread calls new ExecuteOnCaller() - and that's often not the thread you run code in later.

Looper, Handler and the message queue behind all that logic are made of mostly pure Java. The problem with a generic solution is that you can't "inject" code to run into a thread. The thread must periodically check some kind of task queue to see if there is something to run.

If you write code like

    new Thread(new Runnable() {
        @Override
        public void run() {
            while (!Thread.interrupted()) {
                System.out.println("Hello");
            }
        }
    }).start();

Then there is no way to make that thread do anything else but constantly print "Hello". If you could do that it would be like dynamically inserting a jump to other code into the program code. That would IMO be a terrible idea.

    final BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                while (true) {
                    Runnable codeToRunInThisThread = queue.take();
                    codeToRunInThisThread.run();
                }
            } catch (InterruptedException ignored) {}
        }
    }).start();

On the other hand is a simple thread that loops forever on a queue. The thread could do other tasks in between but you have to add a manual check into the code.

And you can send it tasks via

    queue.put(new Runnable() {
        @Override
        public void run() {
            System.out.println("Hello!");
        }
    });

There is no special handler defined here but that's the core of what Handler & Looper do in Android. Handler in Android allows you to define a callback for a Message instead of just a Runnable.

Executors.newCachedThreadPool() and similar do roughly the same thing. There are just multiple threads waiting on code in a single queue.


guava-libraries: is Iterators.cycle() thread-safe?

Question: Suppose I have the following class:

public class Foo {  

    private List<Integer> list = Lists.newArrayList(1, 2, 3, 4, 5);
    private Iterator<Integer> iterator = Iterators.cycle(list);  

    public void bar(){  
        Integer value = iterator.next();  
        doSomethingWithAnInteger(value);
    }  
} 

If an instance of Foo is acessed simultaneously by two threads, I need that each thread gets a different value from iterator.next(). Does the bar() method have to be made synchronized? Or is iterator.next() guaranteed to be thread-safe?

In this example, I am using an ArrayList as the underlying Iterable. Does the thread-safety of the cyclic iterator depend on the specific iterable implementation?

Answer: Pretty much nothing in Guava is guaranteed to be thread safe unless documented as such.

You do not have to synchronize the entire bar method, but you should wrap the call to iterator.next() in a synchronized block. eg:

public void bar(){  
    Integer value;
    synchronized (iterator) {
        value = iterator.next();  
    }
    doSomethingWithAnInteger(value);
}