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.
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.
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
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.
Java handles threads through the Thread
class.
Looking at the properties of the Thread class in Intellij, it looks like this
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).
Thread # interrupt ()
does not immediately stop the running thread. This method just sets the field ʻinterrupted` to true. (This will also 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)
.
There are many ways to write a program that executes something in a separate 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
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 ()`.
newCachedThreadPool()
newFixedThreadPool()
newScheduledThreadPool()
newSingleThreadExecutor()
newWorkStealingPool()
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.
});
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 which
true 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.
Processing that may be interrupted must be implemented with that in mind.
You can check if it was interrupted (whether the ʻinterruptedflag is ON) with
Thread.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
...
}
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.
I'm ignoring the information that the thread has been interrupted and continue
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
}
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.
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.
(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);
}
}
}
WIP
Recommended Posts