Thread pool and lock optimization

Thread Pool:

  The benefits of the thread pool: Thread the application can more fully utilize the CPU, memory, network, IO and other system resources. Creating threads need to open up virtual machine stack, native method stacks, program counter, thread-private memory space.

When these systems need to be recycled thread destruction of resources. So frequent creating and destroying threads will waste a lot of system resources, increase the risk of concurrent programming. In addition, the server load is too large, how to make a new thread to wait or

Friendly denial of service? These are the thread itself can not solve. It is necessary to coordinate a plurality of threads by the thread pool, and achieve a similar primary and secondary threads isolated, regular implementation, task execution period. The role of the thread pool include:

  1): Using the thread pool thread management and reuse, maximum number of concurrent control, etc.

  2): to achieve the task thread queue caching strategies and mechanisms for refusal

  3): to achieve certain time-related functions, such as execution, execution cycle

  4): isolation threaded environment. By configuring two or more thread pools, will slow on one server and other services to isolate and avoid each service threads influence each other.

 

Parameter Description:
1, corePoolSize represent permanent core number of threads, if greater than zero, even if the task is finished executing, the thread will not be destroyed. Therefore, set this value is critical, set too small will lead to thread
  creation and destruction frequently set up over the General Assembly resulting in a waste of resources
2, maximumPoolSize represents the maximum number of threads in the thread pool can accommodate. It must be greater than or equal to 1. If the number of threads to be performed is greater than this value, the cache needs to wait in the queue
3, keepAliveTime indicates that the thread of the thread pool idle time, idle time is reached when keepAliveTime value, the thread will be destroyed, to avoid wasting memory and handle resources. By default, when the thread pool
  when the number of threads is greater than corePoolSize, keepAliveTime only act to achieve thread idle time, until only so far corePoolSize threads. But when the ThreadPoolExecutor
  when allowCoreThreadTimeOut set to true (default false), will be recycled after a timeout core thread. (Typically provided 60s)
. 4, TimeUnit represents time units, keepAliveTime time unit is generally TimeUnit.SECONDS
. 5, showing workQueue buffer queue.
6, threadFactory represents a thread factory. It is used to produce the same task a group of threads. Naming the thread pool is achieved by giving the group name prefix threadFactory increase. When analyzed by jstack, you can know
  threaded tasks which thread is produced by the factory.
7, handler object that represents the implementation of the policy of denial. When the cache exceeds the upper limit workQueue, it can process the request by the policy, which is a simple current limiting protection. Friendly policies can be rejected following
  three ways:
    1): Save the database load shifting. In his spare time and then taken out to perform
    2): Steering a prompt page
    3): Print log

 

Summary Using the thread pool to note the following:

1, a reasonable set various parameters, should be reasonable to set the number of worker threads based on actual business scenarios

2, thread by thread pool resources must be provided, it is not allowed in the application itself explicitly create threads

3, create a thread or a thread pool thread, specify a meaningful name for easy backtracking on error

4, the thread pool is not allowed Executors, but created by ThreadPoolExecutor way, this approach can be more clear operating rules thread pool, to avoid the risk of resource depletion.

Such as creating a thread pool examples:

Copy the code
    / ** 
     * Creates a thread pool for sending mail, the core number of threads is 1 and the maximum number of threads is 5, the thread idle time is 60s, refused to print policy log 
     * / 
    Private static Final ThreadPoolExecutor Executor new new ThreadPoolExecutor = (1, . 5, 60, TimeUnit.SECONDS, a LinkedBlockingQueue new new <the Runnable> (50), new new CustomThreadFactory ( "redeemSendMail"), new new RejectedExecutionHandler () { 
        @Override 
        public void rejectedExecution (R & lt the Runnable, the ThreadPoolExecutor Executor) { 
            // only print log, what nothing 
            LOGGER.error ( "the Task {}, {} from Rejected", r.toString (), executor.toString ()); 
        } 
    });
Copy the code

 

Lock optimization

Adaptive spin locks and lock:

  Mutex impact of synchronization on maximum performance is achieved blocked, suspend and resume the thread of thread operations require from user mode to kernel mode in to complete. These operations to the concurrent performance of the operating system brings a lot of pressure. Meanwhile,

On many applications, sharing data locked state only for a short period of time, this time in order to suspend and resume the thread is not worth it. If more than one processor on a physical machine, allows two or more threads simultaneously in parallel

Execute, we can get behind that request thread lock "Just a minute," but do not give up the processor execution time to see if the thread holding the lock will soon release the lock, in order to allow the thread to wait, we just need to let a thread of execution

Busy cycle, namely the spin, this technique is known as spin locks.

  Spin lock is enabled by default after 1.6, spin-wait can not replace blocked, although avoiding the overhead of thread switching (hang wake, turn user mode kernel mode), but still will take up processor time, so if the lock is occupied time

Very short, then wait for the spin effect will be very good, if the lock takes a long time, then spin the thread will only wasteful consumption of processor resources, a waste of a performance. So spin wait to have a certain limit, if the super-spin

After a limited number of lock is still not successful, then it should be the traditional way to hang a thread. The default is the number of spins 10 times.

  1.6 introduction of adaptive spin lock. Adaptive means that spin time is no longer fixed, but is locked in a state with a spin lock time and the owner is determined by the previous.

 

Lock elimination:

  Lock means to eliminate virtual machine time compiler at run time, some code requirements for synchronization, but can not be detected latched share data to eliminate competition. The main lock to eliminate judgment based on analysis of data from branch escape

Hold, if it is judged in a piece of code, all data on the heap will not escape out by other threads access to, then they can be treated as data on the stack, they are considered private to thread synchronization lock on the need for .

锁粗 of:

  In principle, when we write code, the scope will always recommend sync block restriction as small as possible - but only synchronize the actual scope of shared data, so in order to make the number of operations required to synchronize becomes possible

Small (reducing lock time), if there is lock contention, waiting for the lock that thread can get the lock as soon as possible. But if a series of successive operations on the same object repeatedly lock and unlock the lock operation is even appear in the body of the loop, that that is

Make no thread competition, mutual exclusion synchronization can lead to unnecessary performance overhead frequently. The append StringBuffer class () method is the case, each append () method on the same object are locked, and append ()

It may occur several times in a row.

    @Override
    public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }

If the virtual machine to detect a series of such operations are fragmented lock on the same object, will expand the scope of the lock synchronization (roughening) to the outside of the entire sequence of operations, such as a plurality append () will then be extended to a first append () operation

Until after the last append () operation, so only need to lock it once.

 

Lightweight lock:

  New lock mechanism introduced in 1.6, is relatively lightweight operating system mutex lock be accomplished using conventional terms, the traditional locking mechanism called heavyweight lock. Lightweight lock is not a substitute heavyweight lock, its intention is not multi-line

Cheng premise competition, reduced performance of traditional operating systems Heavyweight locks the mutex consumption generated.

  To understand lightweight lock and biased locking principles and operation of the process, we must understand the JVM object (object header portion) of the internal layout. HotSpot JVM first object (Object Header) information is divided into two parts, with the first portion

Storing runtime data object itself, such as a hash code (hashCode), GC generational age, the lock flag and the like. The official called Mark Word, which is the key to lock and lightweight biased lock. Further directed to a method for storing portion

Pointer object type, then if the array, there will be an extra portion for storing the length of the array.

  Mark Word flag stored content object header in different states is as follows:

  

  During the execution of a lightweight lock: If this synchronization object is not locked (locked flag for the 01 time), the virtual machine will first build a record called lock in the current thread's stack frame when the code to enter the synchronized block (Lock Record)

A space for storing the lock object copy current Mark Word, Displaced added a prefix, i.e. Displaced Mark Word. Then the virtual machine will attempt to use the CAS operations Mark Word object is updated to point to Lock Record

Pointer. If the update action is successful, then the thread owns the lock of the object, and the object's lock Mark Word flag revised to 00, it means that this object is lightweight locked state. If the update operation fails

, The virtual machine will first check whether the object of Mark Word points to the current thread's stack frame, if it shows that the current thread already owns the lock of this object, it can directly enter the synchronized block to continue, otherwise the lock object has already been explained

Other threads seize. If more than two threads competing for the same lock, lightweight lock that is no longer valid, is to be expanded heavyweight lock, the lock status of the flag value becomes 10, Mark Word is stored in pointing heavyweight lock ( mutex)

Pointer, waiting behind the thread must enter the blocked state.

  You can see the lightweight lock locking procedure is achieved by CAS, the same, the unlock process is carried out by the CAS operation, if Mark Word object is still pointing to the record thread lock, then use the CAS operation target current

The Mark Word and thread copy of Displaced Mark Word replacement back if the replacement is successful, the entire synchronization process is complete. If the replacement fails, the other thread tries to acquire the lock, it should at the same time release the lock, call

Wake suspended thread.

  Lightweight lock based program can improve synchronization performance is "for most of the locks are no competition in the entire synchronization cycle," which is an empirical data. If there is no competition, lightweight lock operation using CAS avoid the use of mutex

The amount of overhead, if there is lock contention, then, in addition mutex overhead, additionally happened CAS operation, so in a competitive situation, lightweight lock will be slower than the traditional heavyweight lock.

 

Biased locking:

  1.6 introduced a lock optimization, designed to eliminate data synchronization primitives in the absence of competition, to further improve the operating performance of the program. If the lock is to use lightweight CAS operate in the absence of competitive situations to eliminate the exclusive use of synchronous

The amount that is biased locking in the absence of competition in the entire synchronization are eliminated, and even CAS operations are not done.

  Biased locking of "bias" is eccentric "partial", it means that the lock will be biased in favor of the first to get its thread, if in the next execution, the lock is not acquired by other threads, thread holds the lock will never biased

Far do not need to be synchronized.

  If the virtual machine is turned toward the lock, 1.6 enabled by default, so when the lock object is first acquired by a thread, the virtual object header in the flag is set to 01, that is biased mode. CAS operation to use to get this lock

When the thread ID recorded in the Mark Word object, if the CAS operation is successful, the future holds a biased locking thread lock every time you enter the relevant sync block, the virtual machines can no longer be any synchronization operations. When another thread

Time to try to acquire this lock mode bias came to an end. According to the lock object is currently locked out of state, revoked bias (Revoke Bias) back to the unlocked (flag is 01) or lightweight locking (flag 00) of shape

State, according to the subsequent synchronization process is performed lightweight lock.

  Biased locking can improve performance with synchronized without competition. But it is not always beneficial to the program, if the program most of the locks are always a number of different threads access, then the bias pattern is redundant.

 

Thread Synchronization:

  That is, when there is a thread in the memory operation, other threads can not operate on this memory, wait until the thread is finished, the other threads of memory to operate.

  When multiple threads to the same variable write operation, if the operation is not atomic, dirty data may arise. The so-called atomic means indivisible series of operating instructions, can not be interrupted by any other operations before the execution is completed, then all executed or not executed all. If each thread changes to shared variables are atomic operations, there is no thread synchronization problems.

  i ++ not have the atomic operation, it needs to be divided into three ILOAD -> IINC -> ISTORE.

  CAS (Compare And Swap) operation of atoms comprising

  Way to achieve thread synchronization of many, such as the synchronization method, lock, blocking queues.

 

Volatile

  happen-before: visibility of memory happen-before understanding the operation of the thread start. The method as defined happen before hb (a, b) represents a happen before b. If hb (a, b) and hb (b, c), it can be derived hb (a, c).

That is, if a occurs before b, then a memory operation b are visible, after the operation c, b are also visible.

  Instruction optimization: the computer does not systematically implement the relevant instructions according to the code sequence. The CPU instruction processing optimization information, analyzes which can be combined for taking data, which the stored data can be combined for operation. CPU visit

A distant memory, will look around, if you can access the merger, in order to improve the efficiency.

  happen-before the clock is sequential order, it does not guarantee the visibility of the thread interaction. What is the visibility it? Visibility refers to a thread of instructions to modify the shared variable is visible to other threads, it reflects

Real-time execution of the Transparency Directive. Start talking about the Java Memory Model: each thread has exclusive memory area, such as operating stack, local variables lists. Thread local memory to save a copy of the reference variables in heap memory. Thread

All operations are performed in the local variables memory area, after the end of synchronization to the heap memory (main memory) to go. During this operation, the operation of the copy of the thread, other threads are not visible.

English original meaning is volatile volatile, unstable, extended meaning sensitive. When using a volatile variable modified, means that any operation of this variable will be in main memory, will not produce a copy of the order to ensure shared

Visibility variables, local prevented instruction rearrangement occurs. It's just a lightweight thread operations in a visible way, not in a synchronized manner, if it is to write a scene, will produce thread-safety issues. If it is a write-read many of concurrency scenarios,

Use volatile variables are very appropriate modifications. volatile a write once read many of the most typical application is CopyOnWriteArrayList, all the data in the data is modified it will copy the entire set out to write lock, changes are complete

After then setArray () array to point to the new collection. Use volatile perception can modify the array of thread as soon as possible, without instruction rearrangement operation after visible to other threads.

Source as follows:

Copy the code
public class CopyOnWriteArrayList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
 /** The array, accessed only via getArray/setArray. */ 真正存储元素的数组
    private transient volatile Object[] array;
final void setArray(Object[] a) { array = a; } }
Copy the code

In the actual business, if you are unsure whether a variable is shared by multiple threads concurrently write, insurance practice is to use synchronization code blocks to implement thread synchronization. In addition, since all operations need to be synchronized to the memory variable

So volatile will make the thread execution speed variable, they should be carefully defined and the use of volatile property.

  

  Semaphore Synchronization

  It refers to an amount of signal synchronization between the different threads, a thread of execution to coordinate the order by the amount of transmitted synchronization signal. CountDownLatch time dimension and a dimension based on a signal based Semaphore.

  CountDownLatch

Copy the code
public class CountDownLatch {
    /**
     * Synchronization control For CountDownLatch.
     * Uses AQS state to represent count.
     */
    private static final class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 4982264981922014374L;

        Sync(int count) {
            setState(count);
        }

        int getCount() {
            return getState();
        }

        protected int tryAcquireShared(int acquires) {
            return (getState() == 0) ? 1 : -1;
        }

        protected boolean tryReleaseShared(int releases) {
            // Decrement count; signal when transition to zero
            for (;;) {
                int c = getState();
                if (c == 0)
                    return false;
                int nextc = c-1;
                if (compareAndSetState(c, nextc))
                    return nextc == 0;
            }
        }
    }

    private final Sync sync;
...
}
Copy the code

ReentrantLock and the like which can be seen, are dependent on the visibility of the variable state AQS.

  CountDownLatch: countdown counter, such as daily development often encounter the need to open the main thread to the multi-threaded parallel execution of tasks, and the main thread needs to wait for all the scenes summarize the child thread is finished then, its interior offers

A counter, must specify the initial value of the counter (state) again when the latching structure, and the initial value of the counter must be greater than 0. It also provides a way to countDown operating value of the counter (in the sub-thread) Each call

countDown method counter will be reduced by 1 until the counter value is reduced to 0 (similar to obtain a lock), all due invoked await blocked thread will be woken up.

  

  Semaphore: CountDownLatch class is based on the synchronization count. In the actual coding, based on the synchronization process may be required in the case of an idle signal.

Copy the code
public class Semaphore implements java.io.Serializable {
    private static final long serialVersionUID = -3222578661600680210L;
    /** All mechanics via AbstractQueuedSynchronizer subclass */
    private final Sync sync;

    /**
     * Synchronization implementation for semaphore.  Uses AQS state
     * to represent permits. Subclassed into fair and nonfair
     * versions.
     */
    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 1192457210091910933L;

        Sync(int permits) {
            setState(permits);
        }

        final int getPermits() {
            return getState();
        }
    ...
    }
  // 默认使用非公平锁 static final class NonfairSync extends Sync { private static final long serialVersionUID = -2694183684443567898L; NonfairSync(int permits) { super(permits); } protected int tryAcquireShared(int acquires) { return nonfairTryAcquireShared(acquires); } }
  // 构造方法 public Semaphore(int permits) { sync = new NonfairSync(permits); } ... }
Copy the code

Specifies the number of threads using the constructor method of simultaneous processing of Semaphore, Semaphore's only calling acquire () is successful, we can execute down, semaphore held after the completion of the implementation of release () release, the next thread can obtain immediately This one

Idle semaphore in execution.

Semaphore the same release () method and a CountDownLatch countDown.

acquire () method when idle until there is a semaphore, will perform follow-up code, otherwise, would have been blocked. Semaphore can be understood as the number of locks allowed to create objects specified in the configuration, when the lock free time, you can get a thread

Lock, otherwise it will have to wait. After the completion of the implementation of the thread releases the lock to get the lock.

countDown enable state and release are decremented.

 

end

Guess you like

Origin www.cnblogs.com/yangyongjie/p/12422946.html