Recently, I learned and studied the use of JAVA multi-threading when doing code optimization, and then summarized it after reading the insights of the novices.
1. Inherit the Thread class to implement multi-threading
Although the method that inherits the Thread class is listed as a multi-thread implementation method, Thread is essentially an instance of the Runnable interface, which represents an instance of a thread, and the only way to start a thread is through the start() instance method of the Thread class. The start() method is a native method that will start a new thread and execute the run() method. This method is very simple to implement multi-threading. By directly extending Thread through your own class and rewriting the run() method, you can start a new thread and execute the run() method you define. For example:
public class MyThread extends Thread { public void run() { System.out.println("MyThread.run()"); } } Start the thread in the right place as follows:
MyThread myThread1 = new MyThread(); MyThread myThread2 = new MyThread(); myThread1.start(); myThread2.start();
2. Implement the Runnable interface to implement multi-threading
If your class already extends another class, you cannot extend Thread directly. At this time, you must implement a Runnable interface, as follows:
public class MyThread extends OtherClass implements Runnable { public void run() { System.out.println("MyThread.run()"); } } In order to start MyThread, you need to first instantiate a Thread and pass in your own MyThread instance:
MyThread myThread = new MyThread(); Thread thread = new Thread(myThread); thread.start();
In fact, when a Runnable target parameter is passed to Thread, the run() method of Thread will call target.run(), refer to the JDK source code:
public void run() { if (target != null) { target.run(); } } 3. Use ExecutorService, Callable, and Future to achieve multi-threading with return results
ExecutorService, Callable, and Future objects are actually functional classes in the Executor framework. This is a very detailed explanation of the framework. The thread that returns the result is a new feature introduced in JDK1.5. It is indeed very practical. With this feature, I don’t need to go through a lot of trouble to get the return value, and even if it is implemented, it may be full of loopholes.
Tasks that can return values must implement the Callable interface, and similarly, tasks that do not return values must have the Runnable interface. After executing the Callable task, you can get a Future object. Call get on the object to get the Object returned by the Callable task. Combined with the thread pool interface ExecutorService, you can realize the legendary multi-threading with the return result. Below is a complete multi-threaded test example with returned results. If you have verified it under JDK1.5, you can use it directly. The code is as follows:
import java.util.concurrent.*; import java.util.Date; import java.util.List; import java.util.ArrayList; /** * Thread with return value*/ @SuppressWarnings("unchecked") public class Test { public static void main(String[] args) throws ExecutionException, InterruptedException { System.out.println("------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ Create a thread pool ExecutorService pool = Executors.newFixedThreadPool(taskSize); // Create multiple tasks with return values List<Future> list = new ArrayList<Future>(); for (int i = 0; i < taskSize; i++) { Callable c = new MyCallable(i + " "); // Execute the task and get the Future object Future f = pool.submit(c); // System.out.println(">>>" + f.get().toString()); list.add(f); } // Close the thread pool pool.shutdown(); // Get the running results of all concurrent tasks for (Future f : list) { // Get the return value of the task from the Future object and output it to the console System.out.println(">>>" + f.get().toString()); } Date date2 = new Date(); System.out.println("----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- MyCallable(String taskNum) { this.taskNum = taskNum; } public Object call() throws Exception { System.out.println(">>>" + taskNum + "Task Start"); Date dateTmp1 = new Date(); Thread.sleep(1000); Date dateTmp2 = new Date(); long time = dateTmp2.getTime() - dateTmp1.getTime(); System.out.println(">>>" + taskNum + "Task Termination"); return taskNum + "Task returns the running result, the current task time [" + time + "milliseconds]"; } } Code description:
In the above code, the Executors class provides a series of factory methods for creating the thread pool, and the returned thread pools all implement the ExecutorService interface.
public static ExecutorService newFixedThreadPool(int nThreads)
Creates a thread pool with a fixed number of threads.
public static ExecutorService newCachedThreadPool()
Create a cacheable thread pool, calling execute will reuse previously constructed threads (if the thread is available). If the existing thread is not available, create a new thread and add it to the pool. Terminate and remove threads from the cache that have not been used for 60 seconds.
public static ExecutorService newSingleThreadExecutor()
Create a single-threaded Executor.
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
Create a thread pool that supports timed and periodic task execution, which can be used in most cases instead of the Timer class.
ExecutoreService provides the submit() method, passing a Callable, or Runnable, and returning Future. If the Executor background thread pool has not completed the Callable calculation, this call returns the get() method of the Future object, which will block until the calculation is completed.