multithreading

There are three main ways to realize multithreading

  • extends Thread
  • implements Runnable
  • implements Callable

Implement interface VS inheritance Thread

It is better to implement the interface because:

  • Java does not support multiple inheritance, so if you inherit Thread, you cannot inherit other classes, but you can implement multiple interfaces.
  • The class might just need to be executable, and inheriting the entire Thread class would be too expensive.

 

  • extends Thread

Inheriting Thread code

public class ExtendsThread extends Thread {
    /** * Thread name */
    private String threadName;
 
    /** * constructor **@paramThreadName specifies the threadName */
    public ExtendsThread(String threadName) {
        this.threadName = threadName;
    }
 
    /** * rewrite the run mode */
    @Override
    public void run(a) { System.out.println(threadName); }}Copy the code
public class ThreadMain {
    public static void main(String[] args) {
        ExtendsThread extendsThread = new ExtendsThread("1");
        extendsThread.start();
        extendsThread = new ExtendsThread("2"); extendsThread.start(); }}Copy the code
  • implements Runnable

Implement the Runnable interface

public class ThreadMain {
    public static void main(String[] args) {
        ThreadImplRunnable threadImplRunnable = new ThreadImplRunnable("Thread1");
        new Thread(threadImplRunnable).start();
        threadImplRunnable = new ThreadImplRunnable("Thread2");
        new Thread(threadImplRunnable).start();
        System.out.println("end"); }}Copy the code
public class ThreadImplRunnable implements Runnable {
    /** * Thread name */
    private String threadName;
 
    /** * constructor **@paramThreadName specifies the threadName */
    public ThreadImplRunnable(String threadName) {
        this.threadName = threadName;
    }
    /** * override the run method */
    @Override
    public void run(a) { System.out.println(threadName); }}Copy the code
end
Thread1
Thread2
Copy the code
  • implements Callable

Futuretask.get () gets the returned value

public class ThreadImplCallable<T> implements Callable<T> {
    /** * Thread name */
    private String threadName;
 
    /** * constructor **@paramThreadName specifies the threadName */
    public ThreadImplCallable(String threadName) {
        this.threadName = threadName;
    }
    /** * Override the call method */
    @Override
    public T call(a) throws Exception {
        System.out.println(threadName);
        return(T)threadName; }}Copy the code
public class ThreadMain {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<String> threadImplCallable = new ThreadImplCallable<>("Thread1");
        FutureTask<String> futureTask = new FutureTask<>(threadImplCallable);
        Thread thread = new Thread(futureTask);
        thread.start();
        String rValue = futureTask.get();
        System.out.println("Thread1 return value is " + rValue);
        threadImplCallable = new ThreadImplCallable<>("Thread2");
        futureTask = new FutureTask<>(threadImplCallable);
        thread = new Thread(futureTask);
        thread.start();
        rValue = futureTask.get();
        System.out.println("Thread2 return value is " + rValue);
 
        System.out.println("end"); }}Copy the code
Thread1
Thread1 return value is Thread1
Thread2
Thread2 return value is Thread2
end
Copy the code

 

The thread pool

The top-level interface of the Java thread pool is Executor, which defines only one method, execute. The Executor interface is inherited from the ExecutorService interface, and other related interfaces are defined. ExecutorService includes an abstract class AbstractExecutorService and ScheduledExecutorService, which implements the scheduling interface. Two classes inherit abstract classes. ThreadPoolExecutor and ForkJoinPool, whereas ScheduledThreadPoolExecutor implement interface implementation ScheduledExecutorService interfaces and inheritance ThreadPoolExecutor class, The basic relationship is like this, and the basic common encapsulation methods are in the Executors class, so long as Executors. XXXX can apply the corresponding encapsulation method.

Executor

Executors manage the execution of multiple asynchronous tasks without requiring programmers to explicitly manage the thread lifecycle. Asynchronous here refers to the execution of multiple tasks without interference, without the need for synchronous operations.

Thread pool type

  • newSingleThreadExecutor

A single thread pool. This thread pool has only one thread working, which is equivalent to a single thread executing all tasks in serial. If the unique thread terminates due to an exception, a new thread will replace it. This thread pool ensures that all tasks are executed in the order in which they were submitted.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPool {
    public static void main(String[] args) {
        ExecutorService pool = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 10; i++) {
            pool.execute(() -> {
                System.out.println(Thread.currentThread().getName() + "\t start...."); }); }}}Copy the code
Pool-1-thread-1:.... Pool-1-thread-1:.... Pool-1-thread-1:.... Pool-1-thread-1:.... Pool-1-thread-1:.... Pool-1-thread-1:.... Pool-1-thread-1:.... Pool-1-thread-1:.... Pool-1-thread-1:.... Pool-1-thread-1:....Copy the code
  • newFixedThreadPool

Create a thread pool of fixed size. A thread is created each time a task is submitted until the thread reaches the maximum size of the thread pool. The size of the thread pool stays the same once it reaches its maximum size, and if a thread terminates due to execution exceptions, a new thread is added to the pool.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPool {
    public static void main(String[] args) {
        ExecutorService pool = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10; i++) {
            pool.execute(() -> {
                System.out.println(Thread.currentThread().getName() + "\t start...."); }); }}}Copy the code
pool-1-thread-1Start the train.... pool-1-thread-4Start the train.... pool-1-thread-3Start the train.... pool-1-thread-2Start the train.... pool-1-thread-6Start the train.... pool-1-thread-7Start the train.... pool-1-thread-5Start the train.... pool-1-thread-8Start the train.... pool-1-thread-9Start the train.... pool-1-thread-10Start the train....Copy the code
  • newCachedThreadPool

Create a cacheable thread pool. If the size of the thread pool exceeds the number of threads needed to process the task, some of the idle threads are reclaimed, and as the number of tasks increases, new threads are added to the pool to process the task.

    public static void main(String[] args) {
        ExecutorService pool = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            pool.execute(() -> {
                System.out.println(Thread.currentThread().getName() + "\t start...."); }); }}Copy the code
Pool-1-thread-1:.... Pool-1-thread-2:.... Pool-1-thread-2:.... Pool-1-thread-3:.... Pool-1-thread-3:.... Pool-1-thread-1:.... Pool-1-thread-7:.... Pool-1-thread-5:.... Pool-1-thread-6:.... Pool-1-thread-4:....Copy the code
  • newScheduledThreadPool

This thread pool supports the need to execute tasks regularly and periodically.

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPool {
    public static void main(String[] args) {
        ScheduledExecutorService pool = Executors.newScheduledThreadPool(10);
        for (int i = 0; i < 10; i++) {
            pool.schedule(() -> {
                System.out.println(Thread.currentThread().getName() + "\t start....");
            }, 10, TimeUnit.SECONDS); }}}Copy the code
Pool-1-thread-1:.... Pool-1-thread-2:.... Pool-1-thread-1:.... Pool-1-thread-3:.... Pool-1-thread-7:.... Pool-1-thread-8:.... Pool-1-thread-6:.... Pool-1-thread-5:.... Pool-1-thread-2:.... Pool-1-thread-4:....Copy the code

If you want to execute a periodic task, you can do it once per second.

public static void main(String[] args) {
        ScheduledExecutorService pool = Executors.newScheduledThreadPool(10);
        / / pool. ScheduleWithFixedDelay can also
        pool.scheduleAtFixedRate(() -> {
                System.out.println(Thread.currentThread().getName() + "\t start....");
        }, 1.1, TimeUnit.SECONDS);
}
Copy the code
Pool-1-thread-1:.... Pool-1-thread-1:.... Pool-1-thread-2:.... Pool-1-thread-1:.... Pool-1-thread-3:.... Pool-1-thread-2:.... Pool-1-thread-4:.... Pool-1-thread-1:.... Pool-1-thread-5:.... Pool-1-thread-3:.... Pool-1-thread-3:.... Pool-1-thread-3:.... Pool-1-thread-3:.... Pool-1-thread-3:.... Pool-1-thread-3:.... Pool-1-thread-3:.... Pool-1-thread-9:.... Pool-1-thread-9:....Copy the code
  • newWorkStealingPool

NewWorkStealingPool is a jdk1.8 product that dynamically creates and closes threads based on the desired level of parallelism, reducing contention by using multiple queues, with the underlying ForkJoinPool implemented. ForkJoinPool takes advantage of multi-CPU, multi-core cpus by splitting a task into multiple “small tasks” that can be executed in parallel on multiple processor cores. When multiple “small tasks” are completed, combine the results.

NewWorkStealingPool is suitable for use in time-consuming operations, but newWorkStealingPool is not an extension of ThreadPoolExecutor. It is an extension of the new thread pool class ForkJoinPool. However, all of them are implemented in the same Executors class, so they are suitable for time-consuming tasks due to reasonable use of CPU for task operation (parallel operation)

package org.jeecg.modules.exam.entity;

import org.junit.Test;

import java.util.concurrent.*;

public class WorkStealingPoolTest {
    / / the number of threads
    private static final int threads = 10;
    // This is used to count whether a thread has completed execution
    CountDownLatch countDownLatch = new CountDownLatch(threads);

    /**
     * newFixedThreadPool execute
     *
     * @throws ExecutionException
     * @throws InterruptedException
     */
    @Test
    public void test1(a) throws ExecutionException, InterruptedException {
        System.out.println("---- start ----");
        ExecutorService executorService = Executors.newWorkStealingPool();
        for (int i = 0; i < threads; i++) {
            executorService.execute(() -> {
                try {
                    System.out.println(Thread.currentThread().getName());
                } catch (Exception e) {
                    System.out.println(e);
                } finally{ countDownLatch.countDown(); }}); } countDownLatch.await(); System.out.println("---- end ----");
    }

    /** * newFixedThreadPool submit submit */
    @Test
    public void test2(a) throws InterruptedException {
        System.out.println("---- start ----");
        ExecutorService executorService = Executors.newWorkStealingPool();
        for (int i = 0; i < threads; i++) {
// Callable with return value
            executorService.submit(new Thread(new Runnable() {
                @Override
                public void run(a) {
                    try {
                        System.out.println(Thread.currentThread().getName());
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally{ countDownLatch.countDown(); }}})); } countDownLatch.await(); System.out.println("---- end ----");
    }
    /**
     * newFixedThreadPool submit Callable
     *
     * @throws ExecutionException
     * @throws InterruptedException
     */
    @Test
    public void test3(a) throws ExecutionException, InterruptedException {
        System.out.println("---- start ----");
        ExecutorService executorService = Executors.newWorkStealingPool();
        for (int i = 0; i < threads; i++) {
// Runnable returns a valueFutureTask<? > futureTask =new FutureTask<>(new Callable<String>() {
                /**
                 * call
                 * @return currentThreadName
                 */
                @Override
                public String call(a) {
                    returnThread.currentThread().getName(); }}); executorService.submit(new Thread(futureTask));
            System.out.println(futureTask.get());
        }
        System.out.println("---- end ----"); }}Copy the code