Java concurrent programming (4) performance and scalability, java scalability
Performance and scalability 1. Amdahl's Law
1. Relationship between problems and resources
In some problems, the more resources, the faster the solution. In some cases, the opposite is true:
Note: Each program must have a serial part, and a reasonable analysis of the serial and parallel parts has a great impact on the program; the relationship between the proportion of the serial part and the execution efficiency of multiple cores is exponential.
2. concurrent1_queue
In a multi-core environment, this thread-safe queue is much faster than the queue generated through synchronizedList.
It can be said that the class provided in concurrent is faster than the thread security class generated by the method.
Ii. Thread overhead
Due to the overhead of multithreading, performance must be improved when multithreading is used> concurrency overhead
Overhead of context switching
Memory synchronization overhead
3. Reduce lock competition 1. Reduce lock hold time: narrow the lock range
Private final Map <String, String> attributes = new HashMap <String, String> (); // The entire method locks public synchronized boolean userLocationMatches (String name, String regexp) {String key = "users. "+ name + ". location "; String location = attributes. get (key); if (location = null) return false; else return Pattern. matches (regexp, location);} public boolean userLocationMatches (String name, String regexp) {String key = "users. "+ name + ". location "; String location; // lock only synchronized (this) {location = attributes. get (key) ;}if (location = null) return false; else return Pattern. matches (regexp, location );}
2. Request frequency for Lock reduction: Lock decomposition, lock segmentation...
Lock decomposition: A lock is divided into multiple locks. For example, if you do not need to update multiple state variables in an atomic operation, but each state variable uses the same class lock, it is unnecessary, each irrelevant state variable can use its own lock.
Public class ServerStatusBeforeSplit {public final Set <String> users; public final Set <String> queries; public ServerStatusBeforeSplit () {users = new HashSet <String> (); queries = new HashSet <String> ();} // each method uses the current class instance lock, similar to synchronized (this ), public synchronized void addUser (String u) {users. add (u);} public synchronized void addQuery (String q) {queries. add (q);} public synchronized void removeUser (String u) {users. remove (u);} public synchronized void removeQuery (String q) {queries. remove (q) ;}} public class ServerStatusAfterSplit {public final Set <String> users; public final Set <String> queries; // use the same public ServerStatusAfterSplit () {users = new HashSet <String> (); queries = new HashSet <String> ();} public void addUser (String u) {synchronized (users) {users. add (u) ;}} public void addQuery (String q) {synchronized (queries) {queries. add (q) ;}} public void removeUser (String u) {synchronized (users) {users. remove (u) ;}} public void removeQuery (String q) {synchronized (users) {queries. remove (q );}}}
Lock segmentation: for example, if a map bucket is divided into different segments, each segment has a lock. In this way, different locks can be held when some operations such as get are executed to improve the concurrency efficiency, of course, some operations need to hold the Lock of all segments of the container at the same time, such as clear.
// Implement public class StripedMap for Map multipart locks {// Synchronization policy: buckets [n] guarded by locks [n % N_LOCKS] private static final int N_LOCKS = 16; // Number of locks private final Node [] buckets; // container bucket private final Object [] locks; // synchronize the listener Object array private static class Node {Node next; Object key; object value;} public StripedMap (int numBuckets) {buckets = new Node [numBuckets]; locks = new Object [N_LOCKS]; for (int I = 0; I <N_LOCKS; I ++) locks [I] = new Object ();} private final int hash (Object key) {return Math. abs (key. hashCode () % buckets. length) ;}public Object get (Object key) {int hash = hash (key); // gets the lock of the index area corresponding to the current key, only one lock synchronized (locks [hash % N_LOCKS]) {for (Node m = buckets [hash]; m! = Null; m = m. next) if (m. key. equals (key) return m. value;} return null;} public void clear () {for (int I = 0; I <buckets. length; I ++) {// get the lock corresponding to each I, that is, get all the segment locks of the entire container synchronized (locks [I % N_LOCKS]) {buckets [I] = null ;}}}}
3. Avoid hotspot domain
Hot Spot resource lock competition is fierce, resulting in performance problems
4. Replace the exclusive lock
For example, read-write locks: Read can be parallel to prevent exclusive use; use atomic state quantity; Use concurrent containers; Use immutable objects
5. Reduce context switching
A task is switched in a non-blocking state, similar to a context switch.
For example, log printing and I/O operations may cause a large number of blocking and release, leading to performance problems.