This is the fifth day of my participation in Gwen Challenge
This article introduces several ways to implement multithreading in Java.
No return value
The JDK provides the Thread class and the Runnable interface to allow us to implement our own “Thread” classes.
1. Inherit the Thread class
public class ThreadDemo {
public static class TestThread extends Thread {
@Override
public void run() {
System.out.println("TestThread");
}
}
public static void main(String[] args) {
Thread testThread = newTestThread(); testThread.start(); }}Copy the code
After calling the start method, the thread starts!
2. Implement the Runnable interface
Runnable is implemented as follows. Since Runnable is a functional interface, it can be started by functional programming.
public class Demo {
public static class ThreadDemo implements Runnable {
@Override
public void run() {
System.out.println("ThreadDemo");
}
}
public static void main(String[] args) {
// Traditional startup.
new Thread(new ThreadDemo()).start();
// functional programming startup (java1.8+)
new Thread(() -> {
System.out.println("Thread anonymous Inner class"); }).start(); }}Copy the code
3. Common methods of Thread class
Here are some common Thread methods:
- CurrentThread () : static method that returns a reference to the thread object currently executing;
- Start () : the Java virtual machine calls the run() method in the thread to start execution.
- Yield () : In English, yield means to give up, and again, yield() refers to the willingness of the current thread to relinquish possession of the current processor. It is important to note that even if the current thread calls yield(), the program may continue to run on that thread during scheduling.
- Sleep () : static method that causes the current thread to sleep for a period of time;
- Join () : make the current thread wait for another thread to complete the execution before continuing, internal call is implemented by Object class wait method;
4. Thread class and Runnable interface comparison:
What are the pros and cons of implementing a custom Thread class that inherits Thread classes or implements the Runnable interface?
Because of Java’s single-inheritance, multi-implementation nature, the Runnable interface is more flexible to use than Thread. The Runnable interface appears to be more object-oriented, encapsulating objects in separate threads. The Runnable interface appears, reducing the coupling between threaded objects and threaded tasks. If you don’t need to use many of the Methods of the Thread class when working with threads, the Runnable interface is obviously lighter. Therefore, we usually prefer to customize thread classes using the “implement Runnable interface” approach.
There is a return value form
When creating threads using Runnable and Thread, the run method does not provide a return value. If we need a return value, we can use the Callable and Future provided by the JDK to do so.
1. Callable interface
Callable, like Runnable, is a functional interface that has only one abstract method. The difference is that Callable provides methods that return values and support generics. Callable is typically used in conjunction with the thread pool tool ExecutorService
// Customize Callable
class Task implements Callable<Integer>{
@Override
public Integer call() throws Exception {
// Simulation takes one second
Thread.sleep(1000);
return 2;
}
public static void main(String args[]) throws Exception {
/ / use
ExecutorService executor = Executors.newCachedThreadPool();
Task task = new Task();
Future<Integer> result = executor.submit(task);
// Note that calling the get method blocks the current thread until the result is obtained.
// Therefore, it is recommended to use overloaded GET methods that can set timeout.System.out.println(result.get()); }}Copy the code
2. The Future interface
FutureTask implements the RunnableFuture interface, which inherits both the Runnable and Future interfaces. The JDK provides the FutureTask class for us to use.
// Custom Callable, as above
class Task implements Callable<Integer>{
@Override
public Integer call() throws Exception {
// Simulation takes one second
Thread.sleep(1000);
return 2;
}
public static void main(String args[]) throws Exception {
/ / use
ExecutorService executor = Executors.newCachedThreadPool();
FutureTask<Integer> futureTask = new FutureTask<>(newTask()); executor.submit(futureTask); System.out.println(futureTask.get()); }}Copy the code
When you call the GET method, you can take a value. FutureTask can ensure that tasks are executed only once in high-concurrency environments.