Java SE 8 Concurrency enhancements

1. atomic value

java5 begins, provides classes atomic operation, such as AtomicInteger, AtomicLong etc.

These classes provide methods such as atomic incrementAndGet such operations.

If you want the singular complex operation is required for loop processing compareAndSet

do {

   // .. 计算

} while (!atomicLong.compareAndSet(old, new));

It provides updateAndGet and accumulateAndGet method in java8

atomicLong,updateAndGet(x -> Max.max(x, observed));

atomicLong.accumulateAndGet(observed, Math::max);

It also provides a method corresponding to the original value: getAndUpdate, getAndAccumulate

------------------------------------------------------

 

When a large number of threads access the same original value, because the number of retries optimistic locking too much can lead to performance degradation

Java8 aims to provide a LongAdder and LongAccumulator resolve the issue

The idea of ​​the initial value becomes more neutral elements, different threads may operate on different elements of the calculation, then the final result of the merger operation.

 

E.g:

LongAccumulator adder = new LongAccumulator (Long::sum, 0);

adder.accumulate(value);

In this case included in the plurality of neutral LongAccumulator elements a1, a2 ... aN. The initial value of the neutral element in this example are zero. When calling method accumulate accumulation One of value, wherein the variables are updated as ai = ai op v. In this Strength ai = ai + v;

The method call to get the last time, the result is a1 op a2 op ... aN. As in the above example a1 + a2 + ... aN

------------------------------------------------------

java8 also added StampedLock class implements optimistic reading

Will get a stamp when you call tryOptimisticRead method, and detects when reading the value stamp is valid, you can use this value, otherwise you will get a write lock blocking all read locks

Example:

Copy the code
public class Vector {  
   private int size;  
   private Object[] elements;  
   private StampedLock lock = new StampedLock();  
   public Object get(int n) {  
        long stamp = lock.tryOptimisticRead();  
        Object[] currentElements = elements;  
        int currentSize = size;  
        if (!lock.validate(stamp)) { //  Someone else had a write lock  
             stamp = lock.readLock(); //  Get a pessimistic lock  
             currentElements = elements;  
             currentSize = size;  
             lock.unlockRead(stamp);  
        }  
    return n < currentSize ? currentElements[n] : null;  
  }  
...  
Copy the code

2.ConcurrentHashMap improvements

 

1. Update the value

concurrentHashMap update the value of the time though is thread-safe, but when calculating the updated value of the guarantee because it is not thread-safe, the updated value may be wrong.

A remedy is to replace the use of

Example:

1 do {  
2    oldValue = map.get(word);  
3    newValue = oldValue == null ? 1 : oldValue + 1;  
4 } while (!map.replace(key, oldValue, newValue));  

In addition the use of atomic object may also be used, e.g. CuncurrentHashMap <String, LongAdder>

map.putIfAbsent(word, new LongAdder());  
map.get(word).increment();  

If desired complex calculations, compute the new method may be calculated by a function value

map.compute(word, (k, v) -> v == null ? 1 : v + 1);  

xxxIfPresent and xxxIfAbsent represent existing methods do not yet exist or a case where the value of the value before the operation

 

 

merge method can do some special operation key when the first addition, the second parameter represents the initial value when the key is not yet present

map.merge(word, 1L, (existingValue, newValue) -> existingValue + newValue);  

map.merge(word, 1L, Long::sum);  

--------------------------------------------------------------------------

 

2. bulk data operations

· Search for recipients will each key a function until the function returns a non-null, search terminates and returns a function result

· Reduce cumulative function will be provided by the combination of all key-value pairs

· Foreach on all key application for a function

Each operation has four versions:

• operation Keys: key operation
• operation Values: on the value of the operation
• operation: Operation of keys and values
• operation Entries: Map.Entry for object manipulation.

 

To search, for example, has the following methods:

U searchKeys(long threshold, BiFunction<? super K, ? extends U> f)
U searchValues(long threshold, BiFunction<? super V, ? extends U> f)
U search(long threshold, BiFunction<? super K, ? super V,? extends U> f)
U searchEntries(long threshold, BiFunction<Map.Entry<K, V>, ? extends U> f)

threshold for parallel threshold, if the number of elements contained exceeds the threshold, the operation will be executed in parallel, if you want to always be single-threaded execution, use Long.MAX_VALUE

 

foreach addition to the above methods reduce and form, another form there may be provided a converter function, the application will first converter function, then the result is passed to the consumer function

map.forEach(threshold,  
(k, v) -> k + " -> " + v, // Transformer  
System.out::println); // Consumer  

 

Integer maxlength = map.reduceKeys(threshold,  
String::length, // Transformer  
Integer::max); // Accumulator  

For int, long and double, reduce operation provides a methodology. Beginning toXXX, converts the input values ​​need to be a primitive type, and to specify a default value and accumulator function

long sum = map.reduceValuesToLong(threshold,  
Long::longValue, // Transformer to primitive type  
0, // Default value for empty map  
Long::sum); // Primitive type accumulator  

-----------------------------------------------------------------------------

 


3. Set view

java8 concurrenHashSet class is not provided, but may be obtained by mapping a class through false value concurrentHashMap

NewKeySet static method returns a Set <K> object, which is actually ConcurrentHashMap <K, Boolean> encapsulated object.

Set<String> words = ConcurrentHashMap.<String>newKeySet();  

If you already have a map, keySet method returns a Set of all keys, but you can not add elements to this set, the corresponding value because they can not be added to the map

 

Thus, a method of receiving a default value keySet may solve the above problem, adding elements to the default values ​​set by this

Set<String> words = map.keySet(1L);  
words.add("Java");  

key=java, value = 1L

 

 

 

3. The parallel array operations

Arrays offer many parallel operations

parallelSort sort may be performed in parallel, and may be specified range

1 String contents = new String(Files.readAllBytes(  
2 Paths.get("alice.txt")), StandardCharsets.UTF_8); // Read file into string  
3 String[] words = contents.split("[\\P{L}]+"); // Split along nonletters  
4 Arrays.parallelSort(words);  

 

 1 values.parallelSort (values.length / 2, values.length); // Sort the upper half  

 

parallelSetAll method will be calculated for each parameter based on the calculated values ​​of the functions provided and update

Arrays.parallelSetAll(values, i -> i % 10);  
// Fills values with 0 1 2 3 4 5 6 7 8 9 0 1 2 . . . 

parallelPrefix each array element with the association operation specified prefix accumulation

Suppose array [1, 2, 3, 4, ...], executing the Arrays.parallelPrefix (values, (x, y) -> x * y) after the array is the result

[1, 1 × 2, 1 × 2 × 3, 1 × 2 × 3 × 4, ...]

 


4. Future completed

In the past, methods to obtain results for the Future get, and the call will always get blocked waiting for the results to return

CompletableFuture <T> provides the function "when the result is available, then in the manner provided in process"

1 CompletableFuture<String> contents = readPage(url);  
2 CompletableFuture<List<String>> links = contents.thenApply(Parser::getLinks);  

thenApply method is not blocked, it will return another Future object, when the first Future object is completed, its results will be issued getLinks method

 

 

Future pipeline Similarly Steam line, through one or more conversion process, a terminating end of the last operation.

As a start code may be pipelined

1 CompletableFuture<String> contents  
2 = CompletableFuture.<strong>supplyAsync</strong>(() -> blockingReadPage(url));  

There is also a method runAsync receiving Runnable parameter returns CompletableFuture <void>

 

 

Then you can call thenApply or thenApplyAsync method, run another operation in the same thread or another thread.

These final steps are finished, the results need to be stored somewhere, you need a termination of operations, such as:

1 CompletableFuture<Void> links  
2 = CompletableFuture.supplyAsync(() -> blockingReadPage(url))  
3 .thenApply(Parser::getLinks)  
4 .thenAccept(System.out::println);  

The method of receiving a thenAccept Consumer Interface (return type void), no need to call the get method Future Ideally

 

Here are some common methods:


The method thenCompose do is, it is supposed that there are two call chains, T-> CompletableFuture <U> and U-> CompletableFuture <V> in the case of the successive calls, merged T-> CompletableFuture <V>

Similar conventional method is as follows:

Guess you like

Origin www.cnblogs.com/xkzhangsanx/p/11870235.html