When I read the NioEventLoop section of the Netty source code, I found some confusion about the concept of Java thread & thread pool, so I summarized it further

Java thread pool one: Thread base

Java Thread pool 2: Thread pool principles

Thread creation

There are three main ways to create Java threads: inheriting Thread class, implementing Runable interface, and implementing Callable interface

A Thread is actually created only by calling thread.start (), not by calling thread.run ()

When the calling thread cares about the result of the task execution, we should choose to create the thread in a way that implements the Callable interface

  • Inheritance implements thread creation

    @Test
    public void testCreate_1(a) {
      Thread t = new Thread() {
        @Override
        public void run(a) {
          System.out.println(Thread.currentThread().getName());
          throw newRuntimeException(); }}; t.start(); t.run(); }Copy the code
  • Create a thread that implements the Runnable interface in such a way that the calling thread has no sense of the task thread’s execution result (execution, success, or exception)

    @Test
    public void testCreate_2(a) {
      Thread t = new Thread(() -> System.out.println(Thread.currentThread().getName()));
      t.start();
    }
    Copy the code
  • Implementing the Callable interface, the calling thread retrieves the execution result (return value or exception) from the FutureTask object

    @Test
    public void testCreate_3(a) throws ExecutionException, InterruptedException {
      FutureTask<Integer> task = new FutureTask<>(() -> {
        throw new RuntimeException();
      });
      new Thread(task).start();
      System.out.println(task.get());
    }
    Copy the code

Thread state

We know that Java threads are implemented using kernel threads, so let’s briefly review the state of kernel threads

The state of the kernel thread

  • Ready: The current thread is Ready for system scheduling
  • Running: Enters the Running state when a thread in the Ready state is allocated a time slice
  • Blocking: A running thread enters a Blocking state because another resource is not ready

The status of a Java thread

  • NEW: Instantiates a Thread object until the start method is called
  • RUNNABLE: The executable state in the JVM, corresponding to the Ready or Running state of the kernel thread. Therefore, the thread in this state may not be running, but may be waiting for scheduling
  • WAITING: a state in which another thread needs to wake up before it can re-enter the RUNNABLE state
  • TIMED_WAITING: Timeout waiting, waiting for a certain amount of time or being woken up by another thread before entering the RUNNABLE state
  • BLOCKED: a state of being BLOCKED, especially waiting to enter a synchronized block (to acquire a monitor lock)
  • Termination: the final state

It is blocked only when the monitor lock is pending, and locks implemented in the Java language (ReentrantLock, etc.) are pending. The difference is that the implementation of the monitor lock depends on kernel variables.

Exception handling

If a piece of business logic does not consider a runtime exception, and the runtime exception happens, the corresponding thread crashes directly. So in order to make our programs more robust and stable in multi-threaded environments, we need to catch exceptions.

  • Add exception catching to the entire business logic (of course the code is not very elegant)

    @Test
    public void testExceptionHandle_1(a) {
      new Thread(() -> {
        try {
          //business code
          int a = 1, b = 0;
          a = a / b;
        } catch (Throwable th) {
          //log
        }
      }).start();
    }
    Copy the code
  • Use FutureTask to asynchronously call back handling exceptions (more elegant, separation of business logic and exception handling logic)

    @Test
    public void testExceptionHandle_2(a) {
      // Business logic
      FutureTask<Integer> ft = new FutureTask<>(() -> {
      //business code
      int a = 1, b = 0;
      a = a / b;
      return a;
      });
    
      Thread t = new Thread(() -> {
      ft.run();
      handleResult(ft);
      });
      t.start();
    }
    // Exception handling logic
    private void handleResult(FutureTask<Integer> ft) {
        try {
        System.out.println("the result is " + ft.get());
        } catch (InterruptedException e) {
        //log or ...
        e.printStackTrace();
        } catch (ExecutionException e) {
        //log or ...e.printStackTrace(); }}Copy the code

interrupt

Java interrupts are a means of communication between threads. For example, thread A sends an interrupt signal to thread B, and thread B receives the signal and may or may not process it.

  • Interrupt the associated API
void thread.interrupt();// Instance method - interrupt thread (thread's interrupt flag position is 1)
boolean thread.isInterrupted();// Whether the thread breaks & does not clear the interrupt flag
static boolean Thread.interrupted();// Whether the current thread interrupts & clears the interrupt flag
Copy the code
  • The instance

    Thread T_1 each loop will determine the interrupt status of the current thread, if the current thread has been interrupted (interrupt identifier is 1) directly return;

    The whole communication process: the main thread t_1 interrupt flag position is 1, T_1 get interrupt flag bit is 1, and then end the loop.

    @Test
    public void testInterrupt(a) throws InterruptedException {
      Thread t_1 = new Thread(() -> {
        int i = 0;
        while (true) {
          boolean isInterrupt = Thread.interrupted();
          if (isInterrupt) {
            System.out.println("i am interrupt, return");
            return;
          }
          //business code
          if (i++ % 10000= =0) { System.out.println(i); }}}); t_1.start();for (int i = 0; i < 100000; i++) {
        ;
      }
      t_1.interrupt();
    }
    Copy the code

other

  • Daemon thread

    The daemon thread exits when all user threads in the JVM exit

  • priority

    The higher the priority of a thread, the more likely it is to execute faster or gain more units of executable time. But the priority of Java threads is just a reference, depending on the implementation

  • thread.join()

    The calling thread enters a WAITING state until the thread terminates

  • thread.yield()

    The current thread has relinquished CPU resources and is still in the RUNNABLE state