<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                ## `AtomicInteger` `java.concurrent.atomic`包包含了許多實用的類,用于執行原子操作。如果你能夠在多線程中同時且安全地執行某個操作,而不需要`synchronized`關鍵字或[上一章](http://www.hmoore.net/imnotdown1019/java_core_full/1012271)中的鎖,那么這個操作就是原子的。 本質上,原子操作嚴重依賴于比較與交換(CAS),它是由多數現代CPU直接支持的原子指令。這些指令通常比同步塊要快。所以在只需要并發修改單個可變變量的情況下,我建議你優先使用原子類,而不是[上一章](http://www.hmoore.net/imnotdown1019/java_core_full/1012271)展示的鎖。 > 譯者注:對于其它語言,一些語言的原子操作用鎖實現,而不是原子指令。 現在讓我們選取一個原子類,例如`AtomicInteger`: ~~~java AtomicInteger atomicInt = new AtomicInteger(0); ExecutorService executor = Executors.newFixedThreadPool(2); IntStream.range(0, 1000) .forEach(i -> executor.submit(atomicInt::incrementAndGet)); stop(executor); System.out.println(atomicInt.get()); // => 1000 ~~~ 通過使用`AtomicInteger`代替`Integer`,我們就能線程安全地并發增加數值,而不需要同步訪問變量。`incrementAndGet()`方法是原子操作,所以我們可以在多個線程中安全調用它。 `AtomicInteger`支持多種原子操作。`updateAndGet()`接受lambda表達式,以便在整數上執行任意操作: ~~~java AtomicInteger atomicInt = new AtomicInteger(0); ExecutorService executor = Executors.newFixedThreadPool(2); IntStream.range(0, 1000) .forEach(i -> { Runnable task = () -> atomicInt.updateAndGet(n -> n + 2); executor.submit(task); }); stop(executor); System.out.println(atomicInt.get()); // => 2000 ~~~ `accumulateAndGet()`方法接受另一種類型`IntBinaryOperator`的lambda表達式。我們在下個例子中,使用這個方法并發計算0~1000所有值的和: ~~~java AtomicInteger atomicInt = new AtomicInteger(0); ExecutorService executor = Executors.newFixedThreadPool(2); IntStream.range(0, 1000) .forEach(i -> { Runnable task = () -> atomicInt.accumulateAndGet(i, (n, m) -> n + m); executor.submit(task); }); stop(executor); System.out.println(atomicInt.get()); // => 499500 ~~~ 其它實用的原子類有`AtomicBoolean`、`AtomicLong`和`AtomicReference`。 ## [](https://github.com/wizardforcel/modern-java-zh/blob/master/ch6.md#longadder)`LongAdder` `LongAdder`是`AtomicLong`的替代,用于向某個數值連續添加值。 ~~~java ExecutorService executor = Executors.newFixedThreadPool(2); IntStream.range(0, 1000) .forEach(i -> executor.submit(adder::increment)); stop(executor); System.out.println(adder.sumThenReset()); // => 1000 ~~~ `LongAdder`提供了`add()`和`increment()`方法,就像原子數值類一樣,同樣是線程安全的。但是這個類在內部維護一系列變量來減少線程之間的爭用,而不是求和計算單一結果。實際的結果可以通過調用`sum()`或`sumThenReset()`來獲取。 當多線程的更新比讀取更頻繁時,這個類通常比原子數值類性能更好。這種情況在抓取統計數據時經常出現,例如,你希望統計Web服務器上請求的數量。`LongAdder`缺點是較高的內存開銷,因為它在內存中儲存了一系列變量。 ## [](https://github.com/wizardforcel/modern-java-zh/blob/master/ch6.md#longaccumulator)`LongAccumulator` `LongAccumulator`是`LongAdder`的更通用的版本。`LongAccumulator`以類型為`LongBinaryOperator`lambda表達式構建,而不是僅僅執行加法操作,像這段代碼展示的那樣: ~~~java LongBinaryOperator op = (x, y) -> 2 * x + y; LongAccumulator accumulator = new LongAccumulator(op, 1L); ExecutorService executor = Executors.newFixedThreadPool(2); IntStream.range(0, 10) .forEach(i -> executor.submit(() -> accumulator.accumulate(i))); stop(executor); System.out.println(accumulator.getThenReset()); // => 2539 ~~~ 我們使用函數`2 * x + y`創建了`LongAccumulator`,初始值為1。每次調用`accumulate(i)`的時候,當前結果和值`i`都會作為參數傳入lambda表達式。 `LongAccumulator`就像`LongAdder`那樣,在內部維護一系列變量來減少線程之間的爭用。 ## [](https://github.com/wizardforcel/modern-java-zh/blob/master/ch6.md#concurrentmap)`ConcurrentMap` `ConcurrentMap`接口繼承自`Map`接口,并定義了最實用的并發集合類型之一。Java8通過將新的方法添加到這個接口,引入了函數式編程。 在下面的代碼中,我們使用這個映射示例來展示那些新的方法: ~~~java ConcurrentMap<String, String> map = new ConcurrentHashMap<>(); map.put("foo", "bar"); map.put("han", "solo"); map.put("r2", "d2"); map.put("c3", "p0"); ~~~ `forEach()`方法接受類型為`BiConsumer`的lambda表達式,以映射的鍵和值作為參數傳遞。它可以作為`for-each`循環的替代,來遍歷并發映射中的元素。迭代在當前線程上串行執行。 ~~~java map.forEach((key, value) -> System.out.printf("%s = %s\n", key, value)); ~~~ 新方法`putIfAbsent()`只在提供的鍵不存在時,將新的值添加到映射中。至少在`ConcurrentHashMap`的實現中,這一方法像`put()`一樣是線程安全的,所以你在不同線程中并發訪問映射時,不需要任何同步機制。 ~~~java String value = map.putIfAbsent("c3", "p1"); System.out.println(value); // p0 ~~~ `getOrDefault()`方法返回指定鍵的值。在傳入的鍵不存在時,會返回默認值: ~~~java String value = map.getOrDefault("hi", "there"); System.out.println(value); // there ~~~ `replaceAll()`接受類型為`BiFunction`的lambda表達式。`BiFunction`接受兩個參數并返回一個值。函數在這里以每個元素的鍵和值調用,并返回要映射到當前鍵的新值。 ~~~java map.replaceAll((key, value) -> "r2".equals(key) ? "d3" : value); System.out.println(map.get("r2")); // d3 ~~~ `compute()`允許我們轉換單個元素,而不是替換映射中的所有值。這個方法接受需要處理的鍵,和用于指定值的轉換的`BiFunction`。 ~~~java map.compute("foo", (key, value) -> value + value); System.out.println(map.get("foo")); // barbar ~~~ 除了`compute()`之外還有兩個變體:`computeIfAbsent()`和`computeIfPresent()`。這些方法的函數式參數只在鍵不存在或存在時被調用。 最后,`merge()`方法可以用于以映射中的現有值來統一新的值。這個方法接受鍵、需要并入現有元素的新值,以及指定兩個值的合并行為的`BiFunction`。 ~~~java map.merge("foo", "boo", (oldVal, newVal) -> newVal + " was " + oldVal); System.out.println(map.get("foo")); // boo was foo ~~~ ## [](https://github.com/wizardforcel/modern-java-zh/blob/master/ch6.md#concurrenthashmap)`ConcurrentHashMap` 所有這些方法都是`ConcurrentMap`接口的一部分,因此可在所有該接口的實現上調用。此外,最重要的實現`ConcurrentHashMap`使用了一些新的方法來改進,便于在映射上執行并行操作。 就像并行流那樣,這些方法使用特定的`ForkJoinPool`,由Java8中的`ForkJoinPool.commonPool()`提供。該池使用了取決于可用核心數量的預置并行機制。我的電腦有四個核心可用,這會使并行性的結果為3: ~~~java System.out.println(ForkJoinPool.getCommonPoolParallelism()); // 3 ~~~ 這個值可以通過設置下列JVM參數來增減: ~~~ -Djava.util.concurrent.ForkJoinPool.common.parallelism=5 ~~~ 我們使用相同的映射示例來展示,但是這次我們使用具體的`ConcurrentHashMap`實現而不是`ConcurrentMap`接口,所以我們可以訪問這個類的所有公共方法: ~~~java ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>(); map.put("foo", "bar"); map.put("han", "solo"); map.put("r2", "d2"); map.put("c3", "p0"); ~~~ Java8引入了三種類型的并行操作:`forEach`、`search`和`reduce`。這些操作中每個都以四種形式提供,接受以鍵、值、元素或鍵值對為參數的函數。 所有這些方法的第一個參數是通用的`parallelismThreshold`。這一閾值表示操作并行執行時的最小集合大小。例如,如果你傳入閾值500,而映射的實際大小是499,那么操作就會在單線程上串行執行。在下一個例子中,我們使用閾值1,始終強制并行執行來展示。 ### [](https://github.com/wizardforcel/modern-java-zh/blob/master/ch6.md#foreach)`forEach` `forEach()`方法可以并行迭代映射中的鍵值對。`BiConsumer`以當前迭代元素的鍵和值調用。為了將并行執行可視化,我們向控制臺打印了當前線程的名稱。要注意在我這里底層的`ForkJoinPool`最多使用三個線程。 ~~~java map.forEach(1, (key, value) -> System.out.printf("key: %s; value: %s; thread: %s\n", key, value, Thread.currentThread().getName())); // key: r2; value: d2; thread: main // key: foo; value: bar; thread: ForkJoinPool.commonPool-worker-1 // key: han; value: solo; thread: ForkJoinPool.commonPool-worker-2 // key: c3; value: p0; thread: main ~~~ ### [](https://github.com/wizardforcel/modern-java-zh/blob/master/ch6.md#search)`search` `search()`方法接受`BiFunction`并為當前的鍵值對返回一個非空的搜索結果,或者在當前迭代不匹配任何搜索條件時返回`null`。只要返回了非空的結果,就不會往下搜索了。要記住`ConcurrentHashMap`是無序的。搜索函數應該不依賴于映射實際的處理順序。如果映射的多個元素都滿足指定搜索函數,結果是非確定的。 ~~~java String result = map.search(1, (key, value) -> { System.out.println(Thread.currentThread().getName()); if ("foo".equals(key)) { return value; } return null; }); System.out.println("Result: " + result); // ForkJoinPool.commonPool-worker-2 // main // ForkJoinPool.commonPool-worker-3 // Result: bar ~~~ 下面是另一個例子,僅僅搜索映射中的值: ~~~java String result = map.searchValues(1, value -> { System.out.println(Thread.currentThread().getName()); if (value.length() > 3) { return value; } return null; }); System.out.println("Result: " + result); // ForkJoinPool.commonPool-worker-2 // main // main // ForkJoinPool.commonPool-worker-1 // Result: solo ~~~ ### [](https://github.com/wizardforcel/modern-java-zh/blob/master/ch6.md#reduce)`reduce` `reduce()`方法已經在Java 8 的數據流之中用過了,它接受兩個`BiFunction`類型的lambda表達式。第一個函數將每個鍵值對轉換為任意類型的單一值。第二個函數將所有這些轉換后的值組合為單一結果,并忽略所有可能的`null`值。 ~~~java String result = map.reduce(1, (key, value) -> { System.out.println("Transform: " + Thread.currentThread().getName()); return key + "=" + value; }, (s1, s2) -> { System.out.println("Reduce: " + Thread.currentThread().getName()); return s1 + ", " + s2; }); System.out.println("Result: " + result); // Transform: ForkJoinPool.commonPool-worker-2 // Transform: main // Transform: ForkJoinPool.commonPool-worker-3 // Reduce: ForkJoinPool.commonPool-worker-3 // Transform: main // Reduce: main // Reduce: main // Result: r2=d2, c3=p0, han=solo, foo=bar ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看