[fundamentals of Java Concurrent Programming] 2 Eight common thread creation methods

The previous article mainly introduced the concept of multithreading. This article mainly describes eight common ways to create threads in Java:

  1. Inherit Thread class
  2. Implement the Runable interface
  3. Implement the Callable interface
  4. Thread pool creation
  5. Anonymous Inner Class
  6. Using Lambda expressions
  7. @Async annotation in Spring
  8. Java8 CompletableFuture

1. create by inheriting Thread

This method is the most primitive method of java

/**
* Inherit Thread class
* @date 2018 February 22
*/
public class TestThread extends Thread{
 
    public TestThread (String name) {
        super.setName(name);
    }
    @Override
    public void run() {
    	System.out.println("Current thread: "+Thread.currentThread().getName());
    }
}
public class Main {
 
	public static void main(String[] args) throws Exception {
        TestThread testThread = new TestThread("inherit Thread thread ");
        // Start thread
        testThread.start();
    }
}

Usage:

public class Main {
 
	public static void main(String[] args) throws Exception {
        TestThread testThread = new TestThread("inherit Thread thread ");
        // Start thread
        testThread.start();
    }
}

2. create by implementing Runable

The implementation of the Runable interface solves the problem of Java single inheritance on the basis of inheriting the Thread.

/**
* Implement the Runnable interface
* @date 2018 February 22
*/
public class TestRunnable implements Runnable{
    @Override
    public void run() {
    	System.out.println("Current thread: "+Thread.currentThread().getName());
    }
}

Usage:

public class Main {
 
    public static void main(String[] args) throws Exception {
        // Implement the Runnable interface
        Thread thread = new Thread(new TestRunnable(),"realization Runnable Thread of");
        thread.start();
    }
}

3.Callable and Future

Java provides the Callable interface, which is an enhanced version of the Runnable interface. The Callable interface also provides a call method that can be used as the thread executor, but the call method is more powerful than the run method:
The call() method has a return value
The call() method can declare to throw an exception (it can only be caught internally in normal run methods)

/**
* Implement callable
* @date 2018 February 22
*/
public class TestCallable implements Callable<Integer>{
 
    @Override
    public Integer call() throws Exception {
        System.out.println("Current thread: "+Thread.currentThread().getName());
        return 1;
    }
}

Usage:

public class Main {
 
	public static void main(String[] args) throws Exception {
    	// Callable and Future
        FutureTask<Integer> future = new FutureTask<>(new TestCallable());
        new Thread(future,"Thread with return value").start();
        System.out.println("Return value:"+future.get());
    }
}

4. thread pool creation thread

Thread pool can solve the problem of rational utilization of resources. The Java JUC package provides the creation of four thread pools, as well as the creation method through the thread pool construction method. This article uses the cacheable thread pool creation method:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Thread pool create thread
* @date 2018 February 22
*/
public class ExecutorTest {
 
	public static void main(String[] args) throws Exception {
        // 1. cacheable threads reuse threads
        ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
        for (int i = 0; i < 20; i++) {                                                        
            final int tmp = i;                                                                
            newCachedThreadPool.execute(new Runnable() {                                      
                @Override                                                                     
                public void run() {                                                           
                    System.out.println("threadName:"+Thread.currentThread().getName()+","+tmp);
                }                                                                             
            });                                                                               
        }
	}
}

5. anonymous inner class creation thread

Anonymous inner classes are different in syntax sugar, and the essence is the same as the second

public class Main {
 
	public static void main(String[] args) throws Exception {
    	// Anonymous inner class creation thread
		new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println("Current thread: "+Thread.currentThread().getName());
			}
		}, "Anonymous inner class creation thread").start();
    }
}

6. use Lambda expressions

The use of Lambda expressions is an optimization on the anonymous inner class syntax sugar, which is essentially the same as the second

public class Main {
 
	public static void main(String[] args) throws Exception {
    	// Creating threads using Lambda expressions
		new Thread(() -> System.out.println("Current thread: "+Thread.currentThread().getName())
				, "use Lambda Expression creation thread").start();
    }
}

7. create a thread using @Async

In the Spring framework, the @Async annotation is provided to create threads. Example: if the addUser interface takes 2 seconds and the addMember interface takes 2 seconds, it will take more than 4 seconds if threads are not used. The following is how to optimize the interface loading speed:

@org.springframework.stereotype.Service
class Service {

    /**
     * Add user simulation delay
     */
    @Async
    public Future<Integer> addUser(){
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
        }
        System.out.println("addUser Method execution completed!");
        return new AsyncResult<Integer>(1);
    }

    /**
     * Add member simulation delay
     */
    @Async
    public Future<Integer> addMember(){
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
        }
        System.out.println("addMember Method execution completed!");
        return new AsyncResult<Integer>(1);
    }
}

Test call:

package com.terry.async;

import com.terry.App;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

@SpringBootTest(classes = App.class)
public class TestAsync {

    @Autowired
    private Service service;

    @Test
    public void testAsync(){
        long start = System.currentTimeMillis();
        Future<Integer> member = service.addMember();
        Future<Integer> user = service.addUser();

        try {
            System.out.println("result:" + member.get() + "," + user.get());
            long end = System.currentTimeMillis();
            System.out.println("Interface time:" + (end - start));
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

Printout

8.java8 completable future create thread

Calling the get method using Callable and Future will cause the main thread to block. Java8's completabilefuture can solve this problem:

import java.util.concurrent.CompletableFuture;

/**
 * Java8 CompletableFuture
 * @author terry
 * @version 1.0
 * @date 2022/6/2 17:42
 */
public class TestCompletableFuture {

    public static void main(String[] args) throws InterruptedException {
        System.out.println("Main thread start....");
        CompletableFuture<String> completableFuture1 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "Thread running completed, result true";
        });
        completableFuture1.thenAccept(System.out::println);
        // If no result is obtained, the main thread can still work
        while (true) {
            Thread.sleep(1000);
            System.out.println("Main thread executing....");
        }
    }
}

Print results:

Main thread start....
Main thread executing....
Main thread executing....
Thread running completed, result true
 Main thread executing....
Main thread executing....

Tags: Java Multithreading programming language

Posted by dietkinnie on Fri, 03 Jun 2022 00:49:16 +0530