Author: Tang Tong
brief introduction
Creating threads is the most basic operation in multithreaded programming. Tong Ge summed up that there are about eight ways to create threads, you know?
1. Inherit the Thread class and override the run() method
public class CreatingThread01 extends Thread { @Override public void run() { System.out.println(getName() + " is running"); } public static void main(String[] args) { new CreatingThread01().start(); new CreatingThread01().start(); new CreatingThread01().start(); new CreatingThread01().start(); } }
The disadvantage of inheriting the Thread class and overwriting the run() method is that a class can only inherit one parent class, which cannot be used if the class itself has inherited other classes.
2. Implementing Runnable Interface
public class CreatingThread02 implements Runnable { @Override public void run() { System.out.println(Thread.currentThread().getName() + " is running"); } public static void main(String[] args) { new Thread(new CreatingThread02()).start(); new Thread(new CreatingThread02()).start(); new Thread(new CreatingThread02()).start(); new Thread(new CreatingThread02()).start(); } }
The advantage of implementing Runnable interface is that a class can implement multiple interfaces without affecting its inheritance system.
3. Anonymous inner classes
public class CreatingThread03 { public static void main(String[] args) { //Thread anonymous class, rewriting Thread's run() method new Thread() { @Override public void run() { System.out.println(getName() + " is running"); } }.start(); //Runnable anonymous class to implement its run() method new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " is running"); } }).start(); //Ibid., using lambda expression functional programming new Thread(()->{ System.out.println(Thread.currentThread().getName() + " is running"); }).start(); } }
The way to use anonymous classes is to rewrite Thread's run() method, pass in Runnable's anonymous classes, and lambda's method. Now the third (java 8+) is generally used, which is simple and fast.
4. Implementing Callabe Interface
public class CreatingThread04 implements Callable<Long> { @Override public Long call() throws Exception { Thread.sleep(2000); System.out.println(Thread.currentThread().getId() + " is running"); return Thread.currentThread().getId(); } public static void main(String[] args) throws ExecutionException, InterruptedException { FutureTask<Long> task = new FutureTask<>(new CreatingThread04()); new Thread(task).start(); System.out.println("Waiting for the task to be completed"); Long result = task.get(); System.out.println("Task results:" + result); } }
Implementing the Callabe interface allows you to get the results of thread execution, and FutureTask actually implements the Runnable interface.
5. Timer (java.util.Timer)
public class CreatingThread05 { public static void main(String[] args) { Timer timer = new Timer(); //Execute every 1 second timer.schedule(new TimerTask() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " is running"); } }, 0 , 1000); } }
Timer java.util.Timer can quickly implement timing tasks. TimerTask actually implements the Runnable interface.
6. Thread pool
public class CreatingThread06 { public static void main(String[] args) { ExecutorService threadPool = Executors.newFixedThreadPool(5); for (int i = 0; i < 100; i++) { threadPool.execute(()-> System.out.println(Thread.currentThread().getName() + " is running")); } } }
Thread pool can reuse threads and save system resources.
7. Parallel Computing (Java 8+)
public class CreatingThread07 { public static void main(String[] args) { List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); //Serial, printing result 12345 list.stream().forEach(System.out::print); System.out.println(); //Parallel, print results randomly, such as 35214 list.parallelStream().forEach(System.out::print); } }
Parallel computing can improve the efficiency of program running and multi-threaded parallel execution.
8.Spring Asynchronous Method
First, the springboot startup class is annotated with the @EnableAsync annotation (@EnableAsync is supported by spring, so it's convenient to use springboot for example).
@SpringBootApplication @EnableAsync public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
Second, add the @Async annotation to the method.
@Service public class CreatingThread08Service { @Async public void call() { System.out.println(Thread.currentThread().getName() + " is running"); } }
Then, the test case is directly identical to the general Service approach.
@RunWith(SpringRunner.class) @SpringBootTest(classes = Application.class) public class CreatingThread08Test { @Autowired private CreatingThread08Service creatingThread08Service; @Test public void test() { creatingThread08Service.call(); creatingThread08Service.call(); creatingThread08Service.call(); creatingThread08Service.call(); } }
The results are as follows:
task-3 is running task-2 is running task-1 is running task-4 is running
You can see that the threads used for each method execution are different.
The Spring asynchronous method can be said to be quite convenient. It is suitable for some methods which are logically unrelated and suitable for asynchronous calls, such as the function of sending short messages.
Welcome everyone to pay attention to my public giant [programmer chasing wind], articles will be updated in it, collated information will also be placed in it.
summary
(1) Inheriting the Thread class and overwriting the run() method;
(2) Implementing Runnable interface;
(3) Anonymous internal classes;
(4) Implementing Callabe interface;
(5) Timer (java.util.Timer);
(6) Thread pool;
(7) Parallel computing (Java 8+);
(8) Spring asynchronous method;
welfare
In fact, there are two ways to create threads. One is to inherit the Thread class and override its run() method. The other is to implement the run() method of Runnable interface. What is the relationship between them?
See the following example, inheriting Thread and implementing the Runnable interface at the same time. What should be output?
public class CreatingThread09 { public static void main(String[] args) { new Thread(()-> { System.out.println("Runnable: " + Thread.currentThread().getName()); }) { @Override public void run() { System.out.println("Thread: " + getName()); } }.start(); } }
At this point, we need to look at the source code of the Thread class:
public class Thread implements Runnable { //Thread maintains an instance of Runnable private Runnable target; public Thread() { init(null, null, "Thread-" + nextThreadNum(), 0); } public Thread(Runnable target) { init(null, target, "Thread-" + nextThreadNum(), 0); } private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc, boolean inheritThreadLocals) { // ... //Runnable passed in from the constructor is assigned to target this.target = target; // ... } @Override public void run() { //The default run() method of Thread executes the run() method of target if the target is not empty if (target != null) { target.run(); } } }
Is it a pleasant sight to see here? Since the example above inherits Thread and implements the Runnable interface at the same time, according to the source code, it is actually equivalent to rewriting Thread's run() method, which in fact has nothing to do with target.
So the output of the above example is Thread:Thread-0, which only outputs the contents of the run() method that overrides Thread.
Last
Welcome everyone to exchange, like the article remember to point a compliment yo, thank you for your support!