Java Threading and Multithreading (15)--Thread activity

Source: Internet
Author: User
Tags mutex

When developers use concurrency in their applications to improve performance, developers need to be aware that threads can block each other. When the entire application executes slower than expected, the application does not execute as expected execution time. In this chapter, we need to carefully analyze the active issues that may affect the application of multithreading.

Dead lock

The concept of deadlocks is well known among software developers, and even ordinary computer users often use this concept, although not in the right circumstances. Strictly speaking, a deadlock means that two or more threads are waiting for another thread to release its locked resource, while the thread that requests the resource also locks the resource requested by the other thread itself. As follows:

1for2for resource A

For a better understanding of the problem, refer to the following code:

 Public classDeadlock implements Runnable {Private Static FinalObject Resource1 =NewObject ();Private Static FinalObject Resource2 =NewObject ();Private FinalRandom random =NewRandom (System.currenttimemillis ()); Public Static voidMain (string[] args) {Thread myThread1 =NewThread (NewDeadlock (),"Thread-1"); Thread myThread2 =NewThread (NewDeadlock (),"Thread-2");        Mythread1.start ();    Mythread2.start (); } Public voidRun () { for(inti =0; I <10000; i++) {Boolean b = Random.nextboolean ();if(b) {System. out. println ("["+ Thread.CurrentThread (). GetName () +"] Trying to lock resource 1. ");synchronized(Resource1) {System. out. println ("["+ Thread.CurrentThread (). GetName () +"] Locked resource 1. "); System. out. println ("["+ Thread.CurrentThread (). GetName () +"] Trying to lock resource 2. ");synchronized(RESOURCE2) {System. out. println ("["+ Thread. CurrentThread (). GetName () +"] Locked resource 2. "); }                }            }Else{System. out. println ("["+ Thread.CurrentThread (). GetName () +"] Trying to lock resource 2. ");synchronized(RESOURCE2) {System. out. println ("["+ Thread.CurrentThread (). GetName () +"] Locked resource 2. "); System. out. println ("["+ Thread.CurrentThread (). GetName () +"] Trying to lock resource 1. ");synchronized(Resource1) {System. out. println ("["+ Thread. CurrentThread (). GetName () +"] Locked resource 1. "); }                }            }        }    }}

As you can see from the code above, two threads are started separately and try to lock 2 static resources. But for deadlocks, we need two threads to lock resources in a different order, so we use random instances to select the resources that the thread wants to lock first.

If the Boolean variable b is true , it locks and resource1 then tries to get resource2 the lock. If b it is false , the thread locks first resource2 , but attempts to lock resource1 . The program will encounter a deadlock problem in a moment, and then it will hang until we end the JVM:

[Thread-1] Trying toLockResource1.[thread-1] Locked Resource1.[thread-1] Trying to LockResource2.[thread-1] Locked Resource2.[thread-2] Trying to LockResource1.[thread-2] Locked Resource1.[thread-1] Trying to LockResource2.[thread-1] Locked Resource2.[thread-2] Trying to LockResource2.[thread-1] Trying to LockResource1.

In the above execution, holds the lock, waits for the lock, thread-1 resource2 while the thread holds the lock resource1 thread-2 resource1 , waiting resource2 for the lock.

If we b configure the value true or, we will false not encounter deadlocks, because the order of execution is always consistent, and the order of thread-1 the thread-2 request lock is always consistent. Two threads will request the lock in the same order, so a maximum of one thread will be temporarily blocked and eventually executed sequentially.

Presumably, the following conditions are required to cause a deadlock:

    • Mutex : A resource must exist at some point and can only be accessed by a single thread.
    • Resource hold : When a resource is locked, the thread still needs to get a lock on another resource.
    • There is no preemption policy : When a thread has been holding a resource for some time, there is no mechanism to seize the thread to lock the resource.
    • loop wait : At run time there must be two or more threads that request each other's locked resources.

Deadlocks are more common in multi-threaded applications, although the conditions for deadlocks may appear to be more significant. Developers can avoid deadlocks by breaking the necessary conditions for deadlock formation, as follows:

    • Mutual exclusion: This requirement is usually unavoidable, and resources are often only mutually exclusive access. But that's not always the case. When using a DBMS system, it is possible to replace the original pessimistic locking mechanism with a similar optimistic lock (lock a row in the table when updating the data).
    • There is also a viable option, which is to handle the resource holding, when the lock of a resource is acquired, the lock of other necessary resources is acquired immediately, and if the lock fails, all the previously mutex resources are freed. Of course, this is not always possible, and the resources that might be locked are not known before, or are discarded.
    • If the lock is not immediately available, one way to prevent a deadlock is to configure the lock for the last time-out. A ReentrantLock similar time-out method is provided in the SDK class.
    • From the code above, we can see that if the order of locked resources for each thread is the same, no deadlock will occur. This process can be achieved by abstracting all the code that requests the lock into a single method, which is then called by the thread. This can effectively avoid deadlocks.

In a more advanced application, developers may want to consider implementing a system that detects deadlocks. In this system, some thread-based monitoring is implemented, and logs are logged when the future acquires a lock and attempts to request another lock. If a graph is formed with threads and locks, the developer is able to detect that 2 different threads hold resources and request additional blocking resources at the same time. If the developer can detect and be able to force the blocked thread to release the acquired resources, it can automatically detect deadlocks and automatically fix the deadlock problem.

Hunger

The thread scheduler determines which RUNNABLE threads in the state will execute in the order they are executed. Decisions are generally thread-based, so low-priority threads get less CPU time, and high-priority threads get more CPU time. Of course, this kind of dispatching sounds more reasonable, but sometimes it can cause problems. If a high-priority thread is always executed, then the low-priority thread will not be able to get enough time to execute and be in a state of starvation. Therefore, it is recommended that developers only configure thread priority when it is really necessary.

An example of a very complex thread of starvation is the finalize() method. This feature in the Java language can be used for garbage collection, but when a developer looks at finalizer the priority of a thread, it will find that it is not running at the highest priority level. Therefore, it is possible that the finalize() method will perform longer than other methods.

Another problem with the execution time is that the thread is not defined in what order the code block is synchronized. When many parallel threads need to pass through the encapsulated synchronization code block, there are threads that wait longer than other threads to get into the synchronization code faster. In theory, they may never be able to enter blocks of code. This problem can be solved by using a fair locking scheme. A fair lock takes into account the thread's wait time when selecting the next thread. One of the implementations of a fair lock is java.util.concurrent.locks.ReentrantLock :

If you use ReentrantLock the following constructor:

    /**     * Creates an instance of {@code ReentrantLock} with the     * given fairness policy.     *     * @param fair {@code true} if this lock should use a fair ordering policy     */    publicReentrantLock(boolean fair) {        newnew NonfairSync();    }

Incoming true , then ReentrantLock a fair lock, which allows the thread to get the lock executed sequentially in the pending order. This can reduce the starvation of threads, but it does not completely solve the problem of starvation, after all, the scheduling of threads is dispatched by the operating system. Therefore, the ReentrantLock class only considers the thread that waits for the lock, and the dispatch does not work. For example, although a fair lock is used, the operating system gives low-priority threads a short execution time.

Java Threading and Multithreading (15)--Thread activity

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.