Java thread to understand loosely

To execute asynchronous processing and parallel processing in Java, you need to handle threads. This article is written with the hope that beginners to intermediate Java users will be able to get a rough idea of threads.

What is a thread?

Threads are like the path you take when you run a program. For example

  public static void main(String[] args) {
    run();
  }

  static void run() {
    int result = sum(1, 2);
    System.out.println(result);
  }

  static int sum(int a, int b) {
    return a + b;
  }

When you run the program main () is called, run () is called, sum () is called, System.out.println () is called, and so on, while executing the processes one by one. To go. A thread is the one that executes processing while following this straight path.

All processing runs on threads

For example, if you execute the process from the main function ...

  public static void main(String[] args) {
    Thread currentThread = Thread.currentThread(); //Get your own thread
    System.out.printf("ID:%d, Name:%s, Priority:%d, State:%s%n",
        currentThread.getId(),
        currentThread.getName(),
        currentThread.getPriority(),
        currentThread.getState());
  }

Execution result

ID:1, Name:main, Priority:5, State:RUNNABLE

You can see that it was executed in a thread named main

Try writing code that executes something in another thread

Branch another thread from the main thread and try to execute something asynchronously. New the Thread class and callstart ().

public class Sample {

  public static void main(String[] args) throws Exception {
    Thread thread = new Thread(() -> { //Create Thread. Pass the process you want to execute to the constructor
      for (int i = 1; i < 5; i++) {
        System.out.println("thread: " + i);
        try {
          Thread.sleep(100L);
        } catch (InterruptedException e) {
          return;
        }
      }
    });

    System.out.println("main: 1");

    thread.start(); //Start processing threads

    System.out.println("main: 2");
    Thread.sleep(150L);
    System.out.println("main: 3");

    thread.join(); //Wait for the thread to end (if you don't wait, you don't have to do it)
    System.out.println("main: 4");
  }
}

Output result

main: 1
main: 2
thread: 1
thread: 2
main: 3
thread: 3
thread: 4
main: 4

You can see that the processing of the main thread and the processing of the generated thread are operating independently.

What information does the thread have?

Java handles threads through the Thread class. Looking at the properties of the Thread class in Intellij, it looks like this

Screen Shot 2018-12-17 at 11.40.57.png

I will explain only the ones that you often see.

ID :long

A long type value that is automatically allocated when a thread is created. Unique and immutable.

name :String

The name of the thread. Any name can be set with setName (String). If you create a thread with new Thread (), names like Thread-1 and Thread-2 will be set arbitrarily.

state :Thread.State

Thread status. "Running" or "waiting". The thread has a state and is in one of the following states: NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED.

See Javadoc for details.

interrupted :boolean

Whether the thread was interrupted.

--This value can be set to true with Thread # interrupt () --You can get whether it was interrupted by Thread # isInterrupted () or Thread.interrupted () (the difference will be explained later).

priority :int

Thread priority. When a resource conflict occurs, the thread with the higher priority is executed with priority. The default is 5 (Thread.NORM_PRIORITY), the lowest is 1 (Thread.MIN_PRIORITY), and the highest is 10 (Thread.MAX_PRIORITY). Can be changed with setPriority (int).

daemon: boolean

Is it a daemon thread? If daemon is true, it is called a daemon thread, and if it is false, it is called a user thread. The default is false, which can be set withsetDaemon (boolean).

Various thread programming

There are many ways to write a program that executes something in a separate thread.

How to use raw Thread

Thread is started by putting the process to be executed in the constructor argument of Thread with lambda or new and callingstart ().

Thread thread = new Thread(() -> {
    //Something processing...
});
thread.start(); //Start a thread. "Something" is executed asynchronously

You may inherit Thread and override run. (However, I personally recommend the method ↑, because the processing depends on the Thread class.)

class MyThread extends Thread {
  @Override
  public void run() {
    //Something processing...
  }
}

MyThread thread = new MyThread();
thread.start(); //Start a thread. "Something" is executed asynchronously

How to use Executor

You can easily create something like a thread pool.

ExecutorService threadPool = Executors.newFixedThreadPool(3); //Number of threads=Create 3 thread pools

//Try to put in 100 processing
for (int i = 0; i < 100; i++) {
  threadPool.submit(() -> { //threadPool makes full use of 3 threads to execute the input processing steadily
    //Something processing...
  });
}

//Wait for all submitted processing to finish
threadPool.awaitTermination(1, TimeUnit.MINUTES);

//Stop thread pool
threadPool.shutdown();

There are many other things besides ʻExecutors.newFixedThreadPool ()`.

How to use Completable Future

It's like a Future / Promise in JavaScript. Internally, Executor is used for thread control

//Execute processing asynchronously
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
  //Something processing...
});

//Callback can be registered in the return value CompletableFuture
future.whenComplete((aVoid, throwable) -> { //What is called a JavaScript promise.then()
  //This is called when "something is processed"
  // -If "something" is completed normally, the argument throwable is null.
  // -If an exception occurs in "something", the exception is passed to the argument throwable.
});

Thread interruption

Issue a suspend order

Use Thread # interrupt () if you want to interrupt the processing of a running thread

Thread thread = createNanikanoThread();
thread.start(); //Run the thread
...
thread.interrupt(); //Send a suspend command to a running thread

However, just because ʻinterrupt ()does not mean that the target thread will stop immediately! What happens when you call this method is An image in whichtrue is only set in the boolean field named ʻinterrupted of the target thread (← somewhat rough explanation). Basically, you have to check this ʻinterrupted` flag in the process on the interrupted side.

Confirmation of suspension status

Processing that may be interrupted must be implemented with that in mind. You can check if it was interrupted (whether the ʻinterruptedflag is ON) withThread.interrupted ()`.

//The process of doing something forever
while (true) {
  if (Thread.interrupted()) { //Check if it was interrupted (* When this method is called, the interrupted flag returns to false)
    throw new InterruptedException(); //Throw an exception and exit the process. Basically it's OK if you use InterruptedException
  }
  //Processing something
  ...
}

Calling Thread.interrupted () to check the status resets the interrupted flag to false. (By the way, if you check with Thread.currentThread (). IsInterrupted (), it will not be reset)

Some methods will check the ʻinterruptedstatus. For example,Thread.sleep () will wake up and throw ʻInterruptedException if the ʻinterrupted` flag is set during sleep. (By the way, the interrupted flag is reset to false at this time as well)

//The process of doing something forever
while (true) {
  Thread.sleep(1000L); //Pauses processing for 1 second. InterruptedException is thrown if interrupted during hibernation
  ...
}

Handling of InterruptedException

The fact that an InterruptedException was thrown means that we received the information that the thread was interrupted. Appropriate processing must be done without losing this information.

Bad example 1: Ignore the suspend instruction and continue processing

I'm ignoring the information that the thread has been interrupted and continue

try {
  Thread.sleep(100);
} catch (InterruptedException ex) {
}

Bad example 2: Wrap and throw with another exception

The one you often see

try {
  Thread.sleep(100);
} catch (InterruptedException ex) {
  throw new RuntimeException(ex);
}

The information that the thread has been interrupted has been lost. When catching this exception in the outer process, it will be treated as an unexpected error.

Not bad example: Turn the interrupted flag back on and then wrap and throw with another exception

try {
  Thread.sleep(100);
} catch (InterruptedException ex) {
  Thread.currentThread().interrupt(); // Here!
  throw new RuntimeException(ex);
}

The judgment of the interrupted flag is left to the outside processing. The information that it was interrupted survives. Of course, the process of catching this on the outside has to do something to determine if it has been interrupted.

Personally devised practice: create a dedicated unchecked exception

(I don't know if this method is good. Please let me know if there is a better way ...)

try {
  Thread.sleep(100);
} catch (InterruptedException ex) {
  throw new InterruptedRuntimeException(ex);
}

Be sure to catch this InterruptedRuntimeException in the outer processing and take appropriate processing.

Since it is troublesome to try-catch each time when sleeping, I am making a utility class

public class ThreadUtils {

  /**
   * @param n Sleep time (milliseconds)
   * @throws InterruptedRuntimeException If the thread is interrupted
   */
  public static void sleep(long n) {
    try {
      Thread.sleep(n);
    } catch (InterruptedException ex) {
      throw new InterruptedRuntimeException(ex);
    }
  }

  /**
   *Check if the current thread has been interrupted.
   * @throws InterruptedRuntimeException If the thread is interrupted
   */
  public static void checkForInterruption() {
    if (Thread.interrupted()) {
      throw new InterruptedRuntimeException(ex);
    }
  }
}

About stack trace

WIP

Recommended Posts

Java thread to understand loosely
[java8] To understand the Stream API
Java reference to understand in the figure
Java thread processing
[Java] Map # merge is hard to understand.
[Java] Introduction to Java
Understand java constructor
Two ways to start a thread in Java + @
Changes from Java 8 to Java 11
Sum from Java_1 to 100
[Java] Thread and Runnable
Understand Java 8 lambda expressions
Kotlin's improvements to Java
Thread safe summary ~ Java ~
Introduction to java command
Java Programming Thread Runnable
List processing to understand with pictures --java8 stream / javaslang-
Java classes and instances to understand in the figure
An engineer who doesn't understand Java went to JJUG CCC.
[Java] How to use Map
[Java] New Thread generation method (2)
How to lower java version
Migration from Cobol to JAVA
[Java] How to use Map
Convert Java Powerpoint to XPS
Java adds table to PDF
How to uninstall Java 8 (Mac)
Java to play with Function
Java --How to make JTable
How to use java Optional
New features from Java7 to Java8
How to minimize Java images
How to write java comments
How to use java class
[Java] How to use Optional ②
Connect from Java to PostgreSQL
[Java] How to use removeAll ()
[Java] How to display Wingdings
[Java] Introduction to lambda expressions
[Java] How to use string.format
How to use Java Map
How to set Java constants
Connect to DB with Java
Connect to MySQL 8 with Java
[java] Reasons to use static
Java thread safe for you
List processing to understand with pictures --java8 stream / javaslang --bonus
How to use Java variables
[Java] Introduction to Stream API
Java8 to start now ~ Optional ~
How to convert Java radix
Java concurrency I don't understand
[Java] How to implement multithreading
[Java] How to use Optional ①
From Ineffective Java to Effective Java
How to initialize Java array
[Java] New Thread generation method (1)
[Introduction to rock-paper-scissors games] Java
Input to the Java console
Understand how functional programming was introduced to Java in one shot
Add multi-letter watermark to Java Word