In the last article, we summarized the whole process of multithreaded concurrency. This article started to really open the liver
We learned some of the differences between threads and processes in the last article, so let’s review
The difference between a process and a thread
-
Process is the basic unit of operating system resource allocation, and thread is the minimum unit of operating system resource allocation
-
A process can contain multiple threads, and multiple threads within a process can work together
-
Process has its own independent running space, program switching process overhead; Threads can be regarded as lightweight processes, each thread has its own running stack and PC program counter, thread switching overhead is small
-
The crash of one process in protected mode has no impact on other processes, but the crash of one thread can cause the entire process to crash. Multi-process is more robust than multi-thread
Why use multithreading:
-
** More processor cores: ** More and more processor cores, as well as the use of hyperthreading technology, in order to better use the CPU
-
** Faster response time: ** For some complex code, calculations and merges can be performed concurrently, reducing response time
-
** Better programming model: **Java provides a good programming model for multithreading, making developers more focused on problem solving
Next, thread states, creation methods, and basic operations are introduced
I don’t need to say too much about how important multithreading concurrency isWet brotherWhat I’m sharing is dry stuff
Thread state
Let me give you a picture of the liver:
Cut to the chase and explain
Slow down. Don’t call me. Anyone who doesn’t want to see the picture will explain
A thread has six different states during its run cycle:
-
New: Initial state, the thread has just been created and the start() method has not been called
-
RUNNABLE: Running, thread ready and running are both called RUNNABLE, that is, the call to start has not been granted CPU execution and is executing
-
BLOCKED: a thread that is BLOCKED in a lock, waiting to enter a Synchronized block or method, but has not yet acquired the lock
-
WAITING: a state in which methods such as wait() and join() cause a thread to be in a WAITING state. The CPU does not allocate execution time
-
TIMED_WAITING** : timeout waiting **, similar to waiting, except that it does not wait indefinitely for another thread to wake up, but automatically wakes up after a certain amount of time
-
TERMINATED: termination status, the thread is done, cannot be resurrected, on the termination of the thread again, call start () method will be thrown. Java lang. IllegalThreadStateException anomalies
There are two basic types of threads:
-
** User-level threads: ** the management process is completed by the user program, the operating system core only manages the process
-
** System-level threads: ** Are managed by the operating system kernel, which provides system calls and application program interfaces (apis) that enable user programs to create, execute, and destroy threads
Waiting queue:
A thread must acquire the lock of an object before entering the blocking state. Within the lock, the wait method will immediately release the lock and enter the wait queue. When another thread calls notify(), a random thread in the wait queue is awakened to enter the synchronization queue, waiting for the CPU’s time slice.
NotifyAll (), if executed, wakes up all the waiting threads corresponding to the lock to the synchronization queue, robbing the CPU of execution
Parallelism and concurrency:
-
Parallelism is two or more events occurring at the same time on different entities
-
Synchrony refers to two or more events occurring at the same time interval on the same entity
It can be said that parallelism is for processes and concurrency is for threads
Thread creation
Now that you understand the basics of threads and states, let’s look at how Java implements threads
** Multiple ways to create a new thread: **
-
Inherit Thread and override the run method
-
Implement the Runnable interface, rewrite the run method
-
By implementing the Callable interface, the call() method is implemented and threads are created in conjunction with FutureTask
-
Create files by using a thread pool, such as ExecutorService and Executors
Let’s take a look at these creation methods:
1, inherit Thread, rewrite run method:
public class MyThread extends Thread { @Override public void run() { for (int x = 0; x < 500; x++) { System.out.println(x); }}}Copy the code
Test it out:
Public static void main(String[] args) {// Create two thread objects MyThread my1 = new MyThread(); MyThread my2 = new MyThread(); my1.start(); my2.start(); }Copy the code
Look at the test results (the two threads will execute alternately, but will eventually print all) :
2, implement Runnable interface, override run method:
public class MyRunnable implements Runnable { @Override public void run() { for (int x = 0; x < 500; x++) { System.out.println(x); }}}Copy the code
Test this by passing in a Thread object that requires a new implementation interface:
Public static void main(String[] args) {// create MyRunnable MyRunnable my = new MyRunnable(); Thread t1 = new Thread(my); Thread t2 = new Thread(my); t1.start(); t2.start(); }Copy the code
The test results are the same as above, so without further ado
Create thread with FutureTask by implementing Callable interface and implementing call() method:
-
Implement Callable interface, rewrite call method, can specify the type of return value
-
Create a FutureTask and pass in an instance object that implements the Callable interface
-
Create a thread object and pass in the FutureTask object and start it
public class MyCallable implements Callable{ @Override public String call() throws Exception { for (int i = 0; i < 200; i++) { System.out.println(i); } return “MyCallable”; }}
Test it out:
FutureTask<String> task = new FutureTask<String>(new MyCallable()); Thread t1 = new Thread(task); t1.start(); String result = task.get(); System.out.println(result);Copy the code
Return Callable, success:
4. Create by thread pool, including ExecutorService and Executors:
-
Create ExecutorService objects, and create appropriate thread pools based on specific requirements
-
Executorservice.submit (), pass in a Runnable instance object.(You can also pass in a Callable object, which can be combined with the submit() method to fetch the results of a thread’s execution.)
-
Destroy the thread pool using the executorservice.shutdown () method
//newFixedThreadPool: Creates a thread pool with a fixed length, which controls the maximum number of concurrent threads. The excess threads will wait in the queue. ExecutorService executorService = Executors.newFixedThreadPool(5);
You can submit a Runnable, Callable Task by submitting an instance object to the thread pool. You can also create threads by passing in a ThreadFactory object when creating an ExecutorService
Let’s compare the advantages and disadvantages of each method
-
Thread class inheritance, simple implementation, but because Java is a single inheritance, scalability is not good
-
If you want to access the currentThread, you must use thread.currentthread () to get the currentThread object
-
The Callable interface can implement return values, and it can also inherit from other classes. If you need to access the currentThread, you must use thread.currentthread () to get the currentThread object
-
Thread pool avoids frequent creation and destruction of threads, reduces system overhead, and has concurrency problems
The basic operation and state of a thread
Start methods start and run (object methods) :
-
Run () : Simply encapsulates code that is being executed by a thread. Direct calls are common methods
-
Start () : The thread is started, and the JVM calls its run() method
JVM startup is multithreaded, because only the main thread is started, and the garbage collection thread is also started, we usually use the Runnable interface to decouple concurrent tasks from the running mechanism of the task
Sleep (class method, sleep) :
The pause of a thread in Java refers to the java.lang.sleep method, which is class-owned. This method suspends the currently executing thread for a specified time. If the thread holds the lock, sleep will not release the lock until it finishes
Call sleep to enter the timed wait state, and when the time is up, enter the ready state, not the running state!
When thread.sleep (1000) is called by the main Thread, the Thread is paused and InterruptedException is thrown if interrupted
Yield (release CPU) :
The current thread relinquishes CPU execution, that is, the slice of execution time allocated by the CPU, but does not release resources, and changes from the running state to the ready state, allowing the OS to select the thread again, but possibly this thread again
What it does: Allows threads of the same priority to take turns, but there is no guarantee that they will take turns
In practice, there is no guarantee that yield() will yield because the yielding thread may be selected again by the thread scheduler. Thread.yield() does not block. This method is similar to sleep(), except that the user cannot specify how long to pause.
Join (object method, wait) :
The join() method call waits for this thread to finish before executing another thread
Here’s an example:
public class MyThread extends Thread { @Override public void run() { for (int x = 0; x < 10; x++) { System.out.println(x); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); }}}}Copy the code
This is the thread implementation class, and I’ll call main
public static void main(String[] args) { MyThread t1 = new MyThread(); t1.start(); try { t1.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } system.out.println ("main thread ends "); }Copy the code
Look at the results:
The result is to print the number every second, and finally print the end of the main thread
The main thread will wait for the t1 thread that called the JOIN method to finish and return before continuing to execute
A thread waits for another thread to finish before continuing
Outdated suspend(), resume(), stop() methods:
Everyone should be very familiar with TV, if the TV broadcast program is compared to a Thread operation, then the program pause, resume, stop operation in the Thread API corresponding to the above three methods
These methods are outdated and not recommended
Reason not recommended: After the call, the thread will not release the occupied resource (such as lock), but occupy the resource to enter another state, easy to cause deadlock, resulting in the program work in an uncertain state. It is because of these side effects that it is marked as not recommended
In short, these methods are too violent, unsafe, and can be replaced with wait/notification mechanisms
Interrupt thread:
Thread interrupts had a stop method in previous versions, but this is now obsolete. There is no way to force a thread to terminate. So now how do we terminate the thread?
We use the interrupt() method to set the flag bit, requesting termination of the thread
-
An interrupt doesn’t actually stop a thread, it just sends a signal that sets a flag bit telling the thread that you should terminate
-
The idea is to want the thread to terminate itself, we set up flag bit signals that can terminate the thread according to the business
Note: Calling interrupt does not actually terminate the current thread. It does not affect the state of the thread. It simply sets an interrupt flag bit. This interrupt flag bit can be used to determine when to do something, and when to interrupt is up to us to decide
There are two ways to help check if a thread is interrupted:
-
Interrupted () : Static method that clears flag bits
-
IsInterrupted () : Instance method that does not clear flag bits
If the blocking thread calls the interrupt method, an exception is thrown, the flag bit is set to false, and the thread exits the block
Thread communication:
-
** Waiting notification mechanism: ** Wait (), notify(), and notifyAll(). Thread A calls wait() of S to enter the wait state, and another thread B calls notify() or notifyAll() of S to wake up. Thread A returns to wait() and continues to execute
-
** JOIN: ** is also a communication mechanism where a thread calls thread.join() and waits for the thread to terminate before returning from thread.join()
-
** Pipeline input and output streams: ** The pipe input/output stream is different from the normal file input/output stream or network input/output stream in that it is mainly used for data transfer between threads over the medium of memory. The main implementation is PipedOutputStream, PipedIutputStream, PipedReader, PipedWriter, the first two are byte oriented, and the last two are character oriented
-
**ThreadLocal thread variables: ** a ThreadLocal object is used as a key, and any object is used as a value storage structure attached to the thread. A thread can query the value of a ThreadLocal object on that thread
Lazy, the image comes from the art of Java concurrent programming
Daemon Daemon thread:
We can set the thread to be a daemon thread by **setDaemon(true)**
Daemon threads are threads that provide a common service in the background while the program is running. For example, the garbage collection thread is a good guardian and is not an integral part of the program. Therefore, when all non-daemon threads terminate, the program terminates, killing all daemon threads in the process. Conversely, the program does not terminate as long as any non-daemon threads are running
-
Daemon threads should never access inherent resources, such as files or databases, because it can break at any time or even in the middle of an operation
-
Converting a Thread to a daemon can be done by calling the setDaemon(true) method on the Thread object
The traditional daemon thread is a special thread running in the background, which is independent of the control terminal and lives and dies with the system
Flocculant on
Suggestion: Concurrency is secure, use with caution, do not use caution ~
The more you know, the more you don’t know.