1 Speaking of threads, let’s start with a process. Here is the definition of a process:
Process is the basis of the operating system structure, is a program execution, is a program and its data structure in the processing machine sequential execution of the activities, is the program in a data set to run the process, it is the system for resource allocation and scheduling an independent unit.
Simply speaking, an EXE file in the list of a task manager can be understood as a process, such as Qi.exe is a process, process is the basic operation unit managed by the system.
1.1 What is a thread?
Thread is the smallest unit that the operating system can schedule operations. It is contained in the process and is the actual operating unit in the process.
In simple terms, threads can be thought of as independent subtasks that run in a process. For example, qq.exe has many sub-tasks running at the same time.
1.2 The difference between processes and threads
1.2.1 Scheduling: Thread as the basic unit of scheduling and allocation, process as the basic unit of owning resources.
1.2.2 Concurrency: Concurrent execution can be performed not only between processes, but also between multiple threads of the same process.
1.2.3 Owning Resources: A process is an independent unit of owning resources. A thread basically does not own system resources and only owns a few resources that are essential for running (such as program counters, a set of registers and stacks), but it can share all the resources owned by a process with other threads belonging to the same process. Processes do not share the address space, whereas threads share the address space of their own processes.
1.2.4 System overhead: When creating or undoing a process, the system allocates and reclaims resources for it, so the system overhead is significantly higher than that when creating or undoing a thread.
1.3 What is multithreading?
Multithreading is the execution of multiple threads almost simultaneously.
1.4 Why Multithreading
1.4.1 Using threads Can put the tasks in the program that occupy a long time in the background to process.
1.4.2 User interface is more attractive, so that if a user clicks a button to trigger the processing of an event, a progress bar will pop up to show the progress of the processing.
1.4.3 The efficiency of the program may be improved.
1.4.4 Threads are more useful for waiting tasks such as user input, file reading and network data sending and receiving.
2 Status of the thread
In general, threads can be in the following states: created (new), ready (runnable), running (running), blocked (timed_waiting), waiting, and dead (dead).
3 The use of multithreading
3.1 Inheriting Thread
You can see that it’s alternating, but it’s always going to get to 98.
3.2 Implementing the Runnable Interface
You can still see it alternating, but it’s always going to get to 98.
3.3 Inherit to implement the Callable interface
It is important to note that to implement the Callable interface, you must override the Call () method and use the FutureTask class, which will be covered later when the thread pool is updated.
3.4 Using thread pools For example using the Executor framework
I’m not going to talk about that. More on update thread pools and executors later.
Is it fast to use multithreading?
A: Not necessarily, because multithreading does context switching, which incurs overhead.
4.1 What is Context Switching?
With a single-core CPU, the CPU can only run one thread at a time, and when running one thread switches to running another thread, this is called a thread context switch (similar for processes). Data such as program counters and CPU registers are recorded during the thread context switch.
4.2 How can I Reduce context switching?
4.2.1 Reduce the number of threads
Since a CPU can only execute one thread at a time, and we arrogantly want programs to execute concurrently, the operating system has to constantly switch contexts to make our programs feel like concurrent lines. Therefore, we can reduce the number of context switches simply by reducing the number of threads.
However, if the number of threads is less than the number of CPU cores, and each CPU executes one thread, the CPU should not need to perform a context switch, but this is not the case.
4.2.2 Control the number of threads on the same lock
If multiple threads share the same lock, when one thread acquires the lock, the other threads will block. When the thread releases the lock, the operating system executes from one of the blocked threads, causing another context switch.
Therefore, reducing the number of threads on the same lock also reduces the number of context switches.
4.2.3 Adopt lockless concurrent programming
The task that needs to be executed concurrently is stateless: HASH fragmentation
Stateless means that tasks that are executed concurrently do not share variables; they are executed independently. This type of task can be HASH segmented by ID, and each segment can be executed by one thread.
Tasks that require concurrent execution are stateful: CAS algorithms
If a task needs to modify shared variables, it must control the order in which the threads are executed, otherwise security issues will arise. You can lock tasks to keep them atomic and visible, but this will cause blocking and context switching. To avoid context switching, you can use the CAS algorithm to update shared variables only when they need to be updated internally, without blocking the thread and keeping the update process safe.
5 Disadvantages of using multi-threading:
5.1 Overhead of context switching
When a CPU switches from executing one thread to executing another, it first stores data, Pointers, etc., local to the current thread, and then loads data, Pointers, etc., local to the other thread before executing. This switch is called a context switch. The CPU executes a thread in one context and then switches to another context to execute another thread. Context switching is not cheap. If not necessary, context switches should be reduced.
5.2 Increase resource consumption
Threads need some resources from the computer to run. In addition to the CPU, the thread needs some memory to maintain its local stack. It also requires some resources from the operating system to manage threads.
5.3 Programming is more complex
When multiple threads are accessing shared data, consider thread safety.
6 Thread Safety
6.1 Definition of Thread safety
A class is thread-safe when it can be called safely by multiple threads.
6.2 Thread safety Classification
Thread safety is not a true or false proposition, and shared data can be classified into the following five categories in order of security:
Immutable, absolute thread-safe, relative thread-safe, thread-compatible and thread-antagonistic.
6.2.1. Immutable
An Immutable object is thread-safe. Neither its method implementation nor its caller requires any thread-safe safeguards. As long as an Immutable object is constructed correctly, its externally visible state never changes. You will never see it in an inconsistent state across multiple threads.
Immutable types: basic data types modified by the final keyword; The String; Enumeration type; Number subclasses include numeric wrapper types such as Long and Double, and big data types such as BigInteger and BigDecimal. But AtomicInteger and AtomicLong, both subtypes of Number, are not immutable.
6.2.2 Absolute thread safety
Regardless of the runtime environment, the caller does not need any additional synchronization measures.
6.2.3 Relative thread safety
Relative thread-safety requires that the individual operations on this object are thread-safe, and no additional safeguards are required at the time of invocation. However, for some consecutive calls in a particular order, additional synchronization may be required at the calling side to ensure the correctness of the invocation.
6.2.4 Thread Compatibility
Thread-compatible is when an object itself is not thread-safe, but can be safely used in a concurrent environment by properly using synchronization on the calling side. When we say that a class is not thread-safe, we mean this most of the time. Most classes in the Java API are thread-compatible, such as the collection classes ArrayList and HashMap, which correspond to Vector and HashTable.
6.2.5 Thread Confrontation
Thread opposition is code that cannot be used concurrently in a multithreaded environment, regardless of whether synchronization is taken on the calling end. Because the Java language is inherently multithreaded, thread-opposition code that excludes multithreading is rare, often harmful, and should be avoided.