1. Threads and processes
1. What is the difference between thread and process:
A thread refers to an execution unit that can execute program code during execution. In the Java language, threads have four states: run, ready, suspend and end.
A process refers to a program that is being executed. Threads are also become lightweight processes when they have something to do. They have the smallest unit of program execution. A process can have multiple threads. Each thread shares the program's internal power space (code segments, data segments and heap space) and some process-level resources (such as open files), but each thread has its own space.
2. Why use multi-process ?<br />There are mainly the following aspects at the operating system level:
- Using multi-threading can reduce the response time of the program. If an operation is time-consuming, or is stuck in a long wait, the program will not respond to operations such as mouse and keyboard. After using multi-threading, this time-consuming thread can be allocated to a separate thread for execution, thus making the program better interactivity.
- Thread creation and switching overhead is less expensive compared to processes, while multithreading is very efficient in data sharing.
- Multi-CPU or multi-core computers have the ability to execute multi-threads. If a single process is used, the computer resources will not be reused, resulting in huge waste of resources. Using multithreading on multi-CPU computers can improve CPU utilization.
- Using multithreading can simplify the structure of the program and make it easy to understand and maintain.
2. Creating threads <br />There are generally three methods for multi-threading implementation, and the first two are the most commonly used methods:
1. Inherit the Thread class and override the run() method
Thread is essentially an instance that implements the Runnable interface. It should be noted that after calling the start() method, it does not execute multi-threaded code immediately, but instead makes the thread run. When to run multi-threaded code is determined by the operating system.
Here are the main steps:
(1) Define the subclass of the Thread class and override the run method of the class. The method body of the run method represents the task that the thread wants to complete. Therefore, the run() method is called the execution body.
(2) Create an instance of the Thread subclass, that is, create a thread object.
(3) Call the start() method of the thread object to start the thread.
public class TestThread extends Thread{ public void run() { System.out.println("Hello World"); } public static void main(String[] args) { Thread mThread = new TestThread(); mThread.start(); } } 2. Implement the Runnable interface and implement the run() method of the interface
Here are the main steps:
(1) Customize the class and implement the Runnable interface, and implement the run() method.
(2) Create an instance of the Thread subclass and instantiate the Thread object with the object that implements the Runnable interface as a parameter.
(3) Call Thread's start() method to start the thread.
public class TestRunnable implements Runnable { public void run() { System.out.println("Hello World"); } }public class TestRunnable { public static void main(String[] args) { TestRunnable mTestRunnable = new TestRunnable(); Thread mThread = new Thread(mTestRunnable); mThread.start(); } } 3. Implement the Callable interface and override the call() method
The Callable interface is actually a functional class in the Executor framework. The Callable interface is similar to the Runnable interface, but provides more powerful functions than Runnable, which are mainly manifested in the following 3 points:
(1) Callable can provide a return value after the task is accepted, and Runnable cannot provide this function.
(2) The call() method in Callable can throw exceptions, while the run() method of Runnable cannot throw exceptions.
(3) Running Callable can get a Future object. The Future object represents the result of Ibrahimovic's calculation, and he provides a method to check whether the calculation is completed. Since the thread belongs to an asynchronous calculation model, it is impossible to get the return value of the function from other threads. In this case, Future can be used to monitor the call() method when the target thread calls the call() method. However, when the future get() method is called to get the result, the current thread will block and know the return result of the call() method.
public class TestCallable { //Create thread class public static class MyTestCallable implements Callable { public String call() throws Exception { retun "Hello World"; } } public static void main(String[] args) { MyTestCallable mMyTestCallable= new MyTestCallable(); ExecutorService mExecutorService = Executors.newSingleThreadPool(); Future mfuture = mExecutorService.submit(mMyTestCallable); try { //Waiting for the thread to end and return the result System.out.println(mfuture.get()); } catch (Exception e) { e.printStackTrace(); } } }The output result of the above program is: Hello World
Among these three methods, it is generally recommended to implement the Runnable interface. The reason is: First, the Thread class defines a variety of methods that can be rewritten by derived classes, but only the run() method must be rewritten, which realizes the main function of this thread, which is also the method required to implement the Runnable interface. Secondly, a class should be inherited when they need to be strengthened or modified. Therefore, if there is no need to override other methods of the Thread class, it is better to implement the Runnable interface in this case.
3. Interrupt thread <br />The thread will terminate when the thread's run() method executes the last statement in the method body and returns by executing the return statement, or when an exception that is not caught in the method is not captured. There was a stop method in earlier versions of java, which other threads could call to terminate the thread, but this method has now been deprecated.
The interrupt method can be used to request the termination of the thread. When a thread calls the interrupt method, the thread's interrupt state will be set. This is the boolean flag that no thread has. Each thread should check this flag from time to time to determine whether the thread is interrupted.
To find out whether the thread is set, you can call Thread.currentThread().isInterrupted():
while(!Thread.currentThread().isInterrupted()){do something} However, if a thread is blocked, the interrupt state cannot be detected. This is where the InterruptedException is generated. When an interrupt method is called on a blocked thread (called sleep or wait). The blocking call will be interrupted by the InterruptedException.
If the sleep method (or other interruptible method) is called after each iteration, the isInterrupted detection is unnecessary and useless. If the sleep method is called when the interrupt state is set, it will not sleep but will clear the state and throw an InterruptedException. So if you call sleep in a loop, don't detect the interrupt status, just catch the InterruptedException.
In many published codes, you will find that InterruptedException is suppressed at a very low level:
void myTask(){...try{sleep(50)}catch(InterruptedException e){...}}Don't do this. If you don't think there is any benefit in a catch, there are two reasonable options:
Call Thread.currentThread().interrup() in catch to set the interrupt state. Callers can detect it. A better option is to use throw InterruptedException to mark your method, without using try statement blocks to capture the completed one. This way the caller can catch this exception:
void myTask()throw InterruptedException{sleep(50)}4. The state of the thread
(1). New status (New): A new thread object is created.
(2). Ready state (Runnable): After the thread object is created, other threads call the start() method of the object. The thread in this state is located in the runnable thread pool and becomes runnable, waiting to obtain the CPU usage rights.
(3). Running state: The thread in the ready state acquires the CPU and executes the program code.
(4). Blocked state: Blocked state means that the thread gives up the CPU usage rights for some reason and temporarily stops running. It is not until the thread enters the ready state that it has a chance to go to the running state. There are three types of blockage:
- Waiting to block: The running thread executes the wait() method, and the JVM will put the thread into the waiting pool.
- Synchronous blocking: When the running thread acquires the object's synchronization lock, if the synchronization lock is occupied by other threads, the JVM will put the thread into the lock pool.
- Other blocking: When a running thread executes the sleep() or join() method, or issues an I/O request, the JVM will set the thread to a blocking state. When the sleep() state timed out, join() waited for thread to terminate or timed out, or I/O processing was completed, the thread re-entered to the ready state.
(5). Dead state: The thread has finished executing or exited the run() method due to an exception, and the thread ends its life cycle.
5. Thread priority and daemon thread
1. Thread priority
In Java, each thread has a priority, and by default, a thread inherits the priority of its parent class. You can use the setPriority method to increase or decrease any thread priority. Priority can be set to any value between MIN_PRIORITY (defined as 1 in Thread class) and MAX_PRIORITY (defined as 10 in Thread class). The default priority of threads is NORM_PRIORITY (defined as 5 in Thread class).
Try not to rely on priority. If you really want to use it, you should avoid a common mistake that beginners make. If several high-priority threads do not enter the inactive state, low-priority threads may never be executed. Whenever the scheduler decides to run a new thread, it first selects among the threads with priority, although this will completely starve the low-priority threads.
2. Daemon thread
Call setDaemon(true); converts the thread into a daemon thread. The only purpose of daemon threads is to provide services to other threads. The timing thread is an example. It sends signals to other threads regularly or clears outdated threads that tell cache items. When only daemon threads are left, the virtual machine exits, because if only daemon threads are left, there is no need to continue running the program.
In addition, JVM's garbage collection, memory management and other threads are daemon threads. Also, when doing database applications, the database connection pool used also contains many background threads, monitoring the number of connections, timeout time, status, etc.
The above is about the thread definition, state and properties of Java multithreading. I hope it will be helpful to everyone's learning.