1. Three ways to create a thread and their differences
1.1 Inherits Thread class
First, subclass Thread and override the run() method:
package com.zwwhnly.springbootaction.javabase.thread;
public class MyFirstThread extends Thread {
@Override
public void run(a) {
for (int i = 0; i < 5; i++) {
System.out.printf("[MyFirstThread] output :%d, current thread name :%s\n", i, getName()); }}}Copy the code
Then, create an instance of that subclass and call the start() method to start the thread:
package com.zwwhnly.springbootaction.javabase.thread;
public class ThreadTest {
public static void main(String[] args) {
System.out.println("Main thread starts execution, current thread name :" +
Thread.currentThread().getName());
Thread firstThread = new MyFirstThread();
firstThread.start();
System.out.println("Main thread completes, current thread name :"+ Thread.currentThread().getName()); }}Copy the code
The running result is as follows:
The main thread starts execution, current thread name :main
The main thread is finished. The current thread name is main
[MyFirstThread] Output :0, current Thread name: thread-0
[MyFirstThread] output :1, current Thread name: thread-0
[MyFirstThread] output :2, current Thread name: thread-0
[MyFirstThread] output :3, current Thread name: thread-0
[MyFirstThread] output :4, current Thread name: thread-0
The following two problems can be seen from the running results:
- There are two threads in the program, the main Thread and the custom Thread thread-0.
- call
firstThread.start();
The code in the body of the run() method is not executed immediately, but asynchronously.
The Thread class implements the Runnable interface:
public class Thread implements Runnable {
// Omit other code
}
Copy the code
Here is the key, interview often asked!
1.2 Implementing the Runnable Interface (recommended)
First, define the implementation class for the Runnable interface and implement the run() method:
package com.zwwhnly.springbootaction.javabase.thread;
public class MySecondThread implements Runnable {
@Override
public void run(a) {
for (int i = 0; i < 5; i++) {
System.out.printf("[MySecondThread] output :%d, current thread name :%s\n", i, Thread.currentThread().getName()); }}}Copy the code
We then call the constructor of the Thread class to create the Thread instance and call the start() method to start the Thread:
package com.zwwhnly.springbootaction.javabase.thread;
public class ThreadTest {
public static void main(String[] args) {
Runnable target = new MySecondThread();
Thread secondThread = newThread(target); secondThread.start(); }}Copy the code
The running result is as follows:
The main thread starts execution, current thread name :main
The main thread is finished. The current thread name is main
[MySecondThread] output :0, current Thread name: thread-0
[MySecondThread] output :1, current Thread name: thread-0
[MySecondThread] output :2, current Thread name: thread-0
[MySecondThread] output :3, current Thread name: thread-0
[MySecondThread] output :4, current Thread name: thread-0
As you can see, using this approach gives the same result as inheriting the Thread class.
1.3 Implement the Callable interface
First, define the implementation class for the Callable interface and implement the Call () method:
package com.zwwhnly.springbootaction.javabase.thread;
import java.util.Random;
import java.util.concurrent.Callable;
public class MyThirdThread implements Callable<Integer> {
@Override
public Integer call(a) throws Exception {
Thread.sleep(6 * 1000);
return newRandom().nextInt(); }}Copy the code
Then, create an instance of FutureTask by calling the constructor of the FutureTask class:
Callable<Integer> callable = new MyThirdThread();
FutureTask<Integer> futureTask = new FutureTask<>(callable);
Copy the code
Finally, we call the constructor of the Thread class to create the Thread instance and call the start() method to start the Thread:
package com.zwwhnly.springbootaction.javabase.thread;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class ThreadTest {
public static void main(String[] args) {
System.out.println("Main thread starts execution, current thread name :" +
Thread.currentThread().getName());
Callable<Integer> callable = new MyThirdThread();
FutureTask<Integer> futureTask = new FutureTask<>(callable);
new Thread(futureTask).start();
try {
System.out.println("futureTask.isDone() return:" + futureTask.isDone());
System.out.println(futureTask.get());
System.out.println("futureTask.isDone() return:" + futureTask.isDone());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
System.out.println("Main thread completes, current thread name :"+ Thread.currentThread().getName()); }}Copy the code
The running result is as follows:
The main thread starts execution, current thread name :main
futureTask.isDone() return:false
– 1193053528.
futureTask.isDone() return:true
The main thread is finished. The current thread name is main
Futuretask.get () can be used to retrieve the result of the thread’s execution using the Callable interface, whereas the previous two methods return no value.
Note: When futureTask.get() is called to get the result of the thread’s execution, the main thread blocks until it gets the result.
The blocking effect is shown below:
1.4 the difference between
Here are the key points, often asked in an interview!
- In Java, classes only support single inheritance. If a class inherits from Thread, it cannot inherit from other classes. Therefore, if a class inherits from other classes and must be created as a Thread, it can implement the Runable interface.
- Threads created in a way that implements the Runable interface can handle the same resource and share it.
- Threads created by implementing the Callable interface can obtain the return value of thread execution, whether the execution is complete, and other information.
The second point can be understood with the following example.
Suppose we have a total of 10 tickets (shared resources), in order to improve the efficiency of ticket sales, we open three threads to sell, the code is as follows:
package com.zwwhnly.springbootaction.javabase.thread;
public class SaleTicketThread implements Runnable {
private int quantity = 10;
@Override
public void run(a) {
while (quantity > 0) {
System.out.println(quantity-- + " is saled by "+ Thread.currentThread().getName()); }}}Copy the code
public static void main(String[] args) {
Runnable runnable = new SaleTicketThread();
Thread saleTicketThread1 = new Thread(runnable);
Thread saleTicketThread2 = new Thread(runnable);
Thread saleTicketThread3 = new Thread(runnable);
saleTicketThread1.start();
saleTicketThread2.start();
saleTicketThread3.start();
}
Copy the code
Since all three threads execute asynchronously, the results of each run may be different. The following lists two different results.
Results of the first run:
10 is saled by Thread-0
8 is saled by Thread-0
7 is saled by Thread-0
5 is saled by Thread-0
9 is saled by Thread-1
3 is saled by Thread-1
2 is saled by Thread-1
1 is saled by Thread-1
4 is saled by Thread-0
6 is saled by Thread-2
Second running result:
10 is saled by Thread-0
9 is saled by Thread-0
8 is saled by Thread-0
7 is saled by Thread-0
6 is saled by Thread-0
5 is saled by Thread-0
3 is saled by Thread-0
2 is saled by Thread-0
4 is saled by Thread-2
1 is saled by Thread-1
If you change the saleticketThreads above to inherit the Thread class, you have 3 threads each with 10 tickets, which is 30 tickets, instead of 3 threads sharing 10 tickets.
2. The difference between start() and run() of Thread classes
2.1 the sample
Because of the advantages of implementing the Runnable interface, the implementation of multithreading is basically used in this way, so we changed the definition of MyFirstThread to implement the Runnable interface:
package com.zwwhnly.springbootaction.javabase.thread;
public class MyFirstThread implements Runnable {
@Override
public void run(a) {
for (int i = 0; i < 5; i++) {
System.out.printf("[MyFirstThread] output :%d, current thread name :%s\n", i, Thread.currentThread().getName()); }}}Copy the code
MyFirstThread = MySecondThread; MySecondThread = MyFirstThread;
package com.zwwhnly.springbootaction.javabase.thread;
public class ThreadTest {
public static void main(String[] args) {
System.out.println("Main thread starts execution, current thread name :" +
Thread.currentThread().getName());
Thread firstThread = new Thread(new MyFirstThread());
Runnable target = new MySecondThread();
Thread secondThread = new Thread(target);
firstThread.start();
secondThread.start();
System.out.println("Main thread completes, current thread name :"+ Thread.currentThread().getName()); }}Copy the code
Run results (note: Run multiple times, the results may be different) :
The main thread starts execution, current thread name :main
[MyFirstThread] Output :0, current Thread name: thread-0
[MyFirstThread] output :1, current Thread name: thread-0
[MySecondThread] output :0, current Thread name: thread-1
The main thread is finished. The current thread name is main
[MySecondThread] output :1, current Thread name: thread-1
[MySecondThread] output :2, current Thread name: thread-1
[MySecondThread] output :3, current Thread name: thread-1
[MySecondThread] output :4, current Thread name: thread-1
[MyFirstThread] output :2, current Thread name: thread-0
[MyFirstThread] output :3, current Thread name: thread-0
[MyFirstThread] output :4, current Thread name: thread-0
As can be seen, after the start() method is called, there are three threads in the program, main Thread, thread-0 Thread and thread-1 Thread respectively, and the execution sequence is not in order, so there is uncertainty.
Then change the start() method to the run() method, as follows:
firstThread.run();
secondThread.run();
Copy the code
The result is as follows (run multiple times, the result is the same) :
The main thread starts execution, current thread name :main
Output :0, current thread name :main
Output :1, current thread name :main
[MyFirstThread] output :2, current thread name :main
[MyFirstThread] output :3, current thread name :main
[MyFirstThread] output :4, current thread name :main
[MySecondThread] output :0, current thread name :main
[MySecondThread] output :1, current thread name :main
[MySecondThread] output :2, current thread name :main
[MySecondThread] output :3, current thread name :main
[MySecondThread] output :4, current thread name :main
The main thread is finished. The current thread name is main
As you can see, after the run() method is called, there is only one main thread in the program, and the custom two threads are not started, and the execution order is the same.
1.2 summarize
Here are the key points, often asked in an interview!
- The run() method is just a normal method that waits for the run() method to finish executing, so it is executed serially rather than in parallel.
- The start() method starts a thread that automatically executes the contents of the run() method body when it receives CPU resources, enabling true concurrent execution.
3. Difference between Runnable and Callable
In the previous sections of this article (1.2 implementing the Runnable interface and 1.3 implementing the Callable Interface), we learned how to use the Runnable and Callable interfaces to create threads. Now let’s look at the definitions of the Runnable and Callable interfaces respectively. The Runable interface is defined as follows:
public interface Runnable {
public abstract void run(a);
}
Copy the code
The Callable interface is defined as follows:
public interface Callable<V> {
V call(a) throws Exception;
}
Copy the code
The difference between Runnable and Callable is as follows:
- Runable is executed by run() and Callable by call()
- The call() method can throw an exception, and the run() method can only handle an exception internally
- Threads implementing the Runnable interface do not return values. Threads implementing the Callable interface return results
- Threads that implement the Callable interface can be used with FutureTask to obtain completion, cancellation, execution results, and cancellation of a thread.
4. Source code and reference
Source code address: github.com/zwwhnly/spr… Welcome to download.
The difference between two ways to implement multithreading in Java
Java Thread run() differs from start()
Java Runnable is different from Callable
Callable Runnable comparison and usage
The difference and usage between Runnable and Callable