Day 5: java multithreading (threads)

process and thread

process

        During the execution of the program, the process is dynamic. The files placed on the disk are not processes. Only those in the running state can be called processes; they hold resources and threads. A process is a carrier of resources and threads.

thread

        A thread is the smallest unit of execution in the system; there can be multiple threads in the same process; threads share the resources of the process.

        Interaction of threads: Multiple threads need to communicate properly in order to do their work. There are two modes of interaction: mutual exclusion and synchronization.

the difference

        1. After the operating system introduces the thread mechanism, the process is the unit of resource allocation and scheduling, and the thread is the unit of processor scheduling and allocation. Resources are allocated to processes. Threads only have few resources, and the cost of thread switching is lower than that of processes.

        2. The address spaces of different processes are independent of each other, and threads in the same process share the same address space. Threads of one process are not visible within another process.

        3. When creating or canceling a process, the system must allocate or reclaim resources for it, and the operating system overhead is much greater than the overhead of creating or canceling a thread.

Creation method

Inherit the Thread class

Step 1. Create a thread class and inherit the Thread class;

                2. Rewrite the run() method;

                3. Create a thread class object, and the object calls the start() method to start the thread.

The start() and main() methods are multi-linear and execute two threads at the same time

Note: Thread opening does not necessarily execute immediately, there is CPU scheduling execution

Implement the Runable interface

Steps: 1. Create a thread class and implement the Runable interface;

           2. Implement the run method;

           3. Create a thread class object, new Thread(object).start() to start the thread (agent).

Recommended use: Avoid the limitations of single inheritance, convenient and flexible, and convenient for the same object to be used by multiple threads.

Implement the callable interface

Steps: 1. Inherit the callable interface

           2. Rewrite the call() method, including return value and throwing exception

           3. Create a class object

           4. Create an execution task ExecutorService service = Executors.newFixedThreadPool(3);

           5. Submit and execute Future<Boolean> f1 = service.submit(t1);

           6. Get the result boolean rs1 = f1.get();

           7. Close the service service.shutdownNow();

Control Method

sleep(long millis):

        There must be a time parameter, so that the current thread enters a stagnant state, so the thread executing sleep() will definitely not be executed within the specified time; it can make the thread with low priority get the chance to execute, of course, it can also let the thread with the same priority Level and high priority threads have the opportunity to execute; the lock flag will not be released.

join():

        The thread calling this method finishes executing before that, that is, waits for the thread calling this method to finish executing before continuing. This method also catches exceptions.

yieId():

        The sleep method makes the currently running thread sleep for a period of time and enters the non-running state. The length of this period of time is set by the program. The yield method makes the current thread give up the CPU possession, but the time for giving up is not settable .

        yield() also does not release the lock flag.

        In fact, the yield() method corresponds to the following operations: first check whether there are threads with the same priority in the same runnable state, if so, give the CPU ownership to this thread, otherwise continue to run the original thread. So the yield() method is called "give in", and it gives up the running opportunity to other threads of the same priority.

        The sleep method allows lower-priority threads to get the chance to run, but when the yield() method is executed, the current thread is still in a runnable state, so it is impossible to let the lower-priority thread obtain CPU ownership for a while. In a running system, if the higher-priority thread does not call the sleep method and is not blocked by I/O, then the lower-priority thread can only wait for all higher-priority threads to finish running before they have a chance to run.

        yield() just returns the current thread to the executable state, so the thread executing yield() may be executed again immediately after entering the executable state. So yield() can only give threads of the same priority a chance to execute.

run() and start():

        Put the code that needs to be processed in parallel in the run() method, and the start() method will automatically call the run() method to start the thread, which is stipulated by Java's memory mechanism. And the run() method must be public access, and the return value type is void.

wait()、notify()、notifyAll():

        These three methods are used to coordinate the access of multiple threads to shared data, so these three methods must be used in the Synchronized statement block. The wait() method makes the current thread suspend execution and releases the object lock flag, so that other threads can enter the Synchronized data block, and the current thread is put into the object waiting pool. When the notify() method is called, an arbitrary thread will be removed from the object's waiting pool and placed in the lock flag waiting pool. Only threads in the lock flag waiting pool can acquire the lock flag; if there is no thread in the lock flag waiting pool thread, notify() has no effect.

        notifyAll() removes all threads waiting for that object from the object waiting pool and puts them in the lock flag waiting pool.

synchronized:

        This keyword is used to protect shared data, of course, the premise is to distinguish which data is shared data. Each object has a lock flag. When a thread accesses the object, the data modified by Synchronized will be "locked" to prevent other threads from accessing it. After the current thread accesses this part of the data, the lock flag is released, and other threads can access it.

life cycle

new build

        When the program uses the new keyword to create a thread, the thread is in the newly created state. At this time, only the JVM allocates memory for it and initializes the value of its member variables; the thread object at this time does not show any dynamic characteristics of the thread. , the program will not execute the thread execution body of the thread.

ready

        When the thread object calls the start() method, the thread is in the ready state. The Java virtual machine creates a method call stack and a program counter for it. The thread in this state does not start running, but only indicates that the thread can run. As for when the thread starts running, it depends on the scheduling of the thread scheduler in the JVM

run

        A thread in the running state executes the code in its own run method until it is blocked waiting for a resource or dies when it completes anything. If the execution does not end within a given time slice, it will be replaced by the system and return to the ready state.

block

        When the thread in the running state loses the occupied resources, it enters the blocked state;

Entry blocking:

        ① The thread calls the sleep() method to actively give up the occupied processor resources

        ② The thread calls a blocking IO method, and the thread is blocked before the method returns

        ③ The thread tries to obtain a synchronization monitor, but the synchronization monitor is being held by other threads. About the knowledge of synchronous monitor, there will be a more in-depth introduction later

        ④ The thread is waiting for a notification (notify)

        ⑤ The program calls the suspend() method of the thread to suspend the thread. But this method is prone to deadlock, so you should try to avoid using this method

Unblock:

        ① The thread calling the sleep() method has passed the specified time.

        ② The blocking IO method called by the thread has returned.

        ③ The thread successfully acquired the synchronization monitor it was trying to acquire.

        ④ When a thread is waiting for a notification, another thread sends a notification.

        ⑤ The thread in the suspended state is called the resdme() recovery method.

die

Enter the dead state:

        1. The run() or call() method is executed and the thread ends normally

        2. The thread throws an uncaught exception

        3. Directly call the stop() method to end the thread (easy to cause deadlock)

How to achieve synchronization

concurrency

Concurrency concepts:

        1. Atomicity: the operation is either executed or not executed, and will not be disrupted in the middle;

        2. Visibility: The modification of a variable by a thread is visible to other threads, that is, it can be known that the value has been modified

        3. Order: the execution of the program is executed in the order of the code

        When multi-threads share data, thread insecurity will occur, and multi-thread shared data must be synchronized.

Method to realize

Use synchronized code blocks

use synchronous method

Use mutex ReetrantLock (more flexible code control)

deadlock

Deadlock must occur in concurrency.

cause:

        1. Insufficient system resources

        2. Misallocation of resources

        3. The order in which the progress of the process is running is not appropriate

Production conditions:

        1. Mutual exclusion conditions: The so-called mutual exclusion means that a process monopolizes resources within a certain period of time.

        2. Request and hold conditions: When a process is blocked due to requesting resources, the obtained resources remain unchanged

        3. Non-deprivation conditions: the process has obtained resources, and it cannot be forcibly deprived before it is used up

        4. Circular waiting condition: a number of processes form an end-to-end circular waiting resource relationship

        For example, in the figure below, thread A holds lock 1 and wants to get lock 2, thread B holds lock 2 and wants to get lock 1, but at this time it does not release its own lock, and it will enter endless blocking. The characteristic of a lock is that it can only be owned by one thread;

 If the dependency between multiple threads is circular, and there is a circular lock dependency, then deadlock may also occur.

As shown in the figure below, the loop of three thread deadlocks. Unless the desired lock is obtained, the resource will be released.

 

Deadlock prevention:

        1. Destruction request and maintenance conditions: 1. Apply for all resources at once. After that, you will not apply for resources, and if you do not meet the resource conditions, you will not get resource allocation. 2. Only get the initial resources to run, and then release the resources after running, and request new resources.

        2. Destruction of non-preemptive conditions: When a process obtains a certain non-preemptive resource, it submits a new resource application. If it cannot be satisfied, all resources are released, and if needed in the future, re-apply again.

        3. Destroy the circular waiting condition: number the resources, and request resources in the order of increasing serial numbers. If a process obtains a resource with a high sequence number and wants to obtain a resource with a low sequence number, it needs to release the resource with a high sequence number first.

Unlock the deadlock:

        1. Seize resources. Seize a sufficient amount of resources from one or more processes and allocate them to the deadlocked process to release the deadlocked state.

        2. Terminate (revoke) the process: terminate (revoke) one or more thinking processes until the loop is broken and the system is freed from the deadlock state.

thread communication

        The purpose of communication is for better cooperation. Whether threads are executed alternately or relay-style, they need to be notified by communication.

way of communication:

1.volatile

        Volatile has two major features, one is visibility, and the other is order, prohibiting instruction reordering, and visibility is to allow communication between threads.

Guarantee in principle:

        1. Once all volatile modified variables are changed by a thread, they must be refreshed to the main memory immediately

        2. All volatile modified variables must re-read the value of the main memory before use

2. Wait/notify mechanism

3. join method

4.threadLocal

Guess you like

Origin blog.csdn.net/qq_35056891/article/details/126538728