Eight Ways to Create Threads in the Series of Dead java Threads

(mobile phone horizontal screen source code is more convenient)

problem

(1) What are the ways to create threads?

(2) what scenarios do they have?

brief introduction

Creating threads is the most basic operation in multithreaded programming. Tong Ge summed up that there are probably 8 ways to create threads. Do you know?

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.

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.

Anonymous Inner Class

public class CreatingThread03 {
    public static void main(String[] args) {
        // Thread anonymous class, override 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.

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.

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.

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.

Parallel Computing (Java 8+)

public class CreatingThread07 {

    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
        // Serial, print result is 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.

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 the same as that of the general Service method.

@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.

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;

Egg

There are so many ways to create threads. In fact, there are two ways in essence. One is to inherit the Thread class and rewrite its run() method, the other is to implement the run() method of Runnable interface, so what is the connection between them?

Take the following example, inherit Thread and implement Runnable interface. What should be exported?

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 suddenly clear to see here? Since the above example also inherits Thread and implements the Runnable interface, according to the source code, it is actually equivalent to rewriting the run() method of Thread, which has nothing to do with target in the run() method of Thread.

So, the output of the above example is Thread: Thread-0, which only outputs the contents of the run() method that overrides Thread.

Welcome to pay attention to my public number "Tong Ge read the source code", see more source series articles, and swim together with brother Tong's source ocean.

Tags: Java Spring Programming Lambda

Posted on Mon, 07 Oct 2019 01:47:39 -0700 by pyr