Java thread (2)-thread security

Source: Internet
Author: User

Java thread (2)-thread security
The core of thread-safe code is to manage state access operations, especially shared and variable state access. When multiple threads access the same variable state without proper synchronization, an error occurs in the program. There are three ways to fix this problem: this state variable is not shared among threads. You can change the state variable to an unchangeable variable and use synchronization when accessing the state variable.
Thread security definition:When multiple threads access a class, no matter what scheduling method the runtime environment adopts or how these threads will be executed alternately, and no additional synchronization or collaboration is required in the main code, this class can show correct behavior, so it is called thread security. So what is the correct behavior of the class? It does not violate various immutability conditions that constrain the object state and various posterior conditions that describe the object operation results.
Stateless objects must be thread-safe @ ThreadSafepublic class StatelessFactorizer implements Servlet {

Public void service (ServletRequest req, ServletResponse resp ){
BigInteger I = extractFromRequest (req );
BigInteger [] factors = factor (I );
EncodeIntoResponse (resp, factors );
} Because the thread's access to a stateless object does not affect the correctness of operations in other threads, the stateless object is thread-safe.
Atomicity:In concurrent programming, incorrect results due to improper execution timing are very important, called a race condition. Example: @ NotThreadSafepublic class UnsafeCountingFactorizer implements Servlet {
Private long count = 0; public long getCount () {return count;} public void service (ServletRequest req, ServletResponse resp ){
BigInteger I = extractFromRequest (req );
BigInteger [] factors = factor (I );
++ Count;
EncodeIntoResponse (resp, factors );
}
}
The preceding UnsafeCountingFactorizer class concurrent thread is secure because + + count is a "Read-Modify-write" operation sequence and the result depends on the previous status. When a thread executes a certain step in ++ count, it may be interrupted by other threads. Therefore, when multiple threads concurrently access this code, this vulnerability may cause serious data integrity problems of objects. The most common type of race condition is the check then act operation, which determines the next action through an observation result that may fail. And common "Read-Modify-write" operations. Generally, compound operations that cause the race condition can be converted to atomic operations to ensure thread security. Locking is the most common practice. In a single State, some facilities in the atomic package can be used to ensure the thread security of the compound operation, such as AtomicLong. @ ThreadSafepublic class UnsafeCountingFactorizer implements Servlet {private final AtomicLong count = new AtomicLong (0); public long getCount () {return count. get ();} public void service (ServletRequest req, ServletResponse resp) {BigInteger I = extractFromRequest (req); BigInteger [] factors = factor (I); count. incrementAndGet (); encodeIntoResponse (resp, factors );}}
Lock Mechanism:When a state variable is added to the Servlet, the Servlet state can be managed through thread-safe objects to maintain the thread security of the Servlet. When a class contains multiple states, is it enough to add multiple thread security state variables? In the following example, we assume that we want to improve the performance of Servlet factorization. When two consecutive requests perform factorization for the same value, we can directly use the previous calculation result without re-calculation. @ NotThreadSafepublic class UnsafeCacheingFactorizer implements Servlet {private final AtomicReference LastNumber = new AtomicReference (); Private final AtomicReference LastFactors = new AtomicReference (); Public long getCount () {return count. get ();} public void service (ServletRequest req, ServletResponse resp) {BigInteger I = extractFromRequest (req); if (I. equals (lastNumber. get () {encodeIntoResponse (resp, lastFactors. get ();} else {BigInteger [] factors = factor (I); lastNumber. set (I); lastFactors. set (factors); encodeIntoResponse (resp, lastFactors. get ());}}}
One of the immutability conditions of UnsafeCachingFactorizer is that the product of the factor cached in lastFactors should be equal to the value cached in lastNumber. The above Servlet is correct only when this immutable condition is not damaged. The fact is that although the set method is atomic, The lastNumber and lastFactors cannot be updated at the same time. Likewise, we cannot guarantee that we will get two values at the same time. When the class contains multiple state variables, ensure the consistency of these state variables. To maintain state consistency, you must update all related state variables in a single atomic operation. The lock is required. Built-in lock: the synchronized method uses the class object as the lock. Each java object can be used as a synchronization lock. These locks are called built-in locks or monitoring locks. The thread automatically acquires the lock before entering the synchronization code block, and releases the lock when exiting the synchronization code block. Java built-in locks are equivalent to a mutex lock, which means that only one thread can hold the lock at most. Use synchronized to modify the preceding example: @ ThreadSafepublic class implements Servlet {@ GuardedBy ("this") private final BigInteger lastNumber; @ GuardedBy ("this") private final BigInteger [] lastFactors; public synchronized void service (ServletRequest req, ServletResponse resp) {BigInteger I = extractFromRequest (req); if (I. equals (lastNumber) {encodeIntoResponse (resp, lastFactors);} else {BigI Nteger [] factors = factor (I); lastNumber = I; lastFactors = factors; encodeIntoResponse (resp, factors) ;}} although thread security is ensured, but the concurrency has been reduced to the extreme, and we will continue to improve later. Re-import: in java, the built-in locks can be reentrant. Therefore, if a thread tries to obtain a lock that is already held by itself, the request will succeed. "Re-import" means that the granularity of the lock acquisition operation is "Thread", rather than "call ". For example, if the built-in lock is not reentrant, the code will be deadlocked.
Public class Widget {public synchronized void doSomething (){.....}} public class LoggingWidget extends Widget {public synchronized void doSomething (){...... super. doSomething ();}}
Use locks to protect the status:For variable state variables that may be accessed by multiple threads at the same time, you must hold the same lock when accessing the variable. In this case, we call the state variable protected by this lock. Each shared and variable should be protected by only one lock, so that maintenance personnel can know which lock is used. For each immutable condition that contains multiple variables, all the variables involved must be protected by the same lock, making it impossible for other threads to damage the integrity condition.
Activity and performance:Do not hold a lock when performing a long computing operation or operations that may not be completed quickly (for example, network I/O or console I/O. We can usually reduce the synchronization code to improve the concurrency of the program, but to judge the reasonable size of the synchronization code block, we need to weigh between various design requirements, including security (this need must be met), simplicity and performance. There are usually mutual constraints between simplicity and performance. When implementing a synchronization policy, do not blindly sacrifice simplicity for performance (which may compromise security ). In the SynchronizedFactorizer class we used earlier, the Service is a synchronized method, so there is only one thread to execute at a time, which violates the original intention of the Servlet framework. The concurrency is 0, even if multiple CPUs exist, the last servlet request must wait until the previous request is complete before proceeding to the next step. Next we will reduce the scope of the synchronization code block, separate the calculation steps from the synchronization, and use the same lock to protect the immutable condition of the class. @ ThreadSafepublic class CachedFactorizer implements Servlet {
@ GuardedBy ("this") private final BigInteger lastNumber; @ GuardedBy ("this") private final BigInteger [] lastFactors; public void service (ServletRequest req, ServletResponse resp ){
BigInteger I = extractFromRequest (req );
BigInteger [] factors = null;
Synchronized (this ){
If (I. equals (lastNumber )){
Factors = lastFactors. clone ();
}
}
If (factors = null ){
BigInteger [] factors = factor (I );
Synchronized (this ){
LastNumber = I;
LastFactors = factors. clone ();
}
}
EncodeIntoResponse (resp, lastFactors );
}
}

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.