When it comes to Java, we have to talk about multi-threading. Even if you don’t want to say it, the interviewer has to let you say it, right? When it comes to multi-threading, threads are not allowed to be mentioned (isn’t this nonsense). When it comes to threads, we have to talk about Runnable
and Callable
.
To say that it is familiar is to say that it is really familiar. When I first learned multi-threading, the first example was probably as follows.
new Thread(new Runnable() { @Override public void run() { System.out.println("Execution Thread" + Thread.currentThread().getName()); } }).start();
When programming in java, sometimes you will see Runnable
, and sometimes you will see Callable
. What exactly are these two, what are the differences, and when should you use Runnable
, when should you use Callable
. Let’s take a look today
Runnable
Since the birth of Java, Runnable
has existed, the oldest among the elders. Before 1.5, if you wanted to use threads, you had to implement Runnable
. Because with JDK1.5, JDK added Callable
.
@FunctionalInterface public interface Runnable { public abstract void run(); }
@FunctionalInterface
indicates that this interface is a functional interface. The functional interface was only added in JDK8 to implement functional programming, like Lambada expressions. So in JDK1.7, there is no @FunctionalInterface
modification, it’s simple. We found the Ruunable
implementation of JDK1.7, which looks like this.
public interface Runnable { public abstract void run(); }
If a thread class implements the Runnable interface, the class must define a parameterless method named run. A class that implements the Runnable interface can be run by instantiating a Thread instance and passing itself as the target.
For example, first define a RunnableThread
class, implement the Runnable
interface, and then override the run
method.
public class RunnableThread implements Runnable{ @Override public void run() { System.out.println("Current thread name" + Thread.currentThread().getName()); } }
The startup code is as follows:
RunnableThread runnableThread = new RunnableThread(); Thread thread = new Thread(runnableThread); thread.start();
Callable
Callable was only added in JDK1.5 to make up for the defect of Runnable not returning a value.
@FunctionalInterface public interface Callable<V> { V call() throws Exception; }
Similar to Runnable, @FunctionalInterface was also added later and can be ignored, just for functional writing. The Callable interface has only one call method and a generic return value that can return any type.
//Callable example public class MyCallable implements Callable<Integer> { @Override public Integer call() throws Exception { System.out.println("This is a Callable task."); return 123; // Return an integer } }
The calling code is as follows:
ExecutorService executor = Executors.newSingleThreadExecutor(); Future<Integer> future = executor.submit(new MyCallable()); Integer result = future.get(); // Get the result of task execution
The difference between Runnable
and Callable
Runnable
and Callable
are both interfaces used for multi-threaded programming in Java. The main differences between them are:
-
Return value: The
run()
method ofRunnable
has no return value, while thecall()
method ofCallable
has one. Return value of generic type. -
Exception throwing: The
run()
method ofRunnable
cannot throw an exception, and thecall()
method ofCallable
Exceptions can be thrown. You need to use thetry-catch
statement or throw the exception upward. -
Usage:
Runnable
is usually used as a parameter to start a thread, whileCallable
is usually used as a parameter to submit a task to the thread pool, so that the results of task execution can be obtained.
Runnable
and Callable usage notes
When using Runnable
and Callable
, you need to pay attention to the following matters:
-
Return value processing:
Runnable
‘srun()
method does not have a return value, butCallable
‘scall()
method does A return value of a generic type. ForCallable
tasks, the results of task execution can be obtained through theFuture
object. When getting results, you can choose to wait for task execution to complete (callfuture.get()
) or set a timeout (callfuture.get(timeout, unit)
). -
Exception handling: The
run()
method ofRunnable
cannot throw an exception, but thecall()
method ofCallable
can throw an exception. When usingCallable
, you need to pay attention to catching exceptions that may be thrown and handle them appropriately. -
Thread pool usage: Normally,
Runnable
tasks are suitable to be started usingThread
, whileCallable
tasks are suitable to be submitted using the thread pool. Thread pools can better manage and reuse thread resources and improve program performance and efficiency. -
Task cancellation: You can cancel the task being executed through the
cancel()
method of theFuture
object. However, it should be noted that if the task has already started execution, it may not be aborted immediately. Additionally, if the task has been completed or canceled, calling thecancel()
method again will returnfalse
. -
Concurrency safety: When using
Runnable
andCallable
in a multi-threaded environment, you need to pay attention to the concurrency safety of the data. To ensure the correctness of shared data access, you can use synchronization mechanisms (such assynchronized
keyword,Lock
interface) or use concurrent containers (such asConcurrentHashMap
,CopyOnWriteArrayList
, etc.) to ensure thread safety. -
Inter-thread communication:
Runnable
andCallable
tasks can interact through shared variables or inter-thread communication mechanisms. For example, you can use thewait()
andnotifyAll()
methods to implement the waiting and waking up mechanism.
How to choose between Runnable
and Callable
The basic principle of choice is whether a return value is required. If a return value is not required, just choose Runnable without hesitation. If there is a return value, then don’t hesitate and don’t think about using shared variables. Runnable does not accept throwing exceptions, but Callable can throw exceptions.
Runnable is suitable for purely asynchronous processing logic. For example, a report is calculated regularly every day, and the report is stored in a database or other places. It only needs to be calculated and does not need to be displayed immediately. The display content is obtained separately in other methods.
For example, for those non-core functions, after the core process is completed, the non-core functions can be executed by themselves. Whether they are successful or not is not particularly important. For example, in a shopping order process, placing orders, reducing inventory, adding to the user’s order list, and deducting money are the core functions. After that, you can start a new thread to send APP notifications and SMS notifications.
For more news information, please visit Angyan Data (https://www.ayshuju.com)