Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Returning Values from Java Threads with Callable and Future

Tech 2

Runnible tasks cannot produce a value; they only execute side effects. To compute a result on a background thread and retrieve it later, use Callable<T> together with ExecutorService.submit, which returns a Future<T>. A Future is a handle to the ongoing comptuation that can be queried for completion and used to obtain the result.

Key points:

  • Implement Callable<T>#call() to return a value or throw an exception.
  • Submit the task via ExecutorService#submit to get a Future<T>.
  • Future#get() blocks until the task finishes; Future#isDone() lets you check completion first to avoid blocking unnecessarily.

Example (polling for compleetion to avoid a blokcing get):

package example.concurrent;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class CallableResultDemo {
    private static final long WORK_MILLIS = 3000L;
    private static final long POLL_MILLIS = 1000L;

    public static void main(String[] args) throws InterruptedException {
        ExecutorService pool = Executors.newFixedThreadPool(
                Runtime.getRuntime().availableProcessors());

        try {
            Callable<String> compute = () -> {
                Thread.sleep(WORK_MILLIS);
                return "Value produced by worker thread";
            };

            Future<String> resultRef = pool.submit(compute);

            int ticksRemaining = (int) (WORK_MILLIS / POLL_MILLIS);
            while (!resultRef.isDone()) {
                System.out.println("Waiting (" + ticksRemaining-- + ")...");
                Thread.sleep(POLL_MILLIS);
            }

            try {
                String value = resultRef.get();
                System.out.println(value);
            } catch (ExecutionException ex) {
                System.err.println("Task failed: " + ex.getCause());
            }
        } finally {
            pool.shutdown();
        }
    }
}

Possible output:

Waiting (3)...
Waiting (2)...
Waiting (1)...
Value produced by worker thread

Notes:

  • Calling get() immediately will block the caller until completion. Checking isDone() first avoids blocking and lets you perform other work or show progress.
  • Alternatively, use get(timeout, unit) too avoid waiting indefinitely if the task might take too long.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.