【记录】并发编程-学习日志(六)

6. 共享模式之无锁

6.1 提出问题【引言】

package com.rui.six;

import java.util.ArrayList;
import java.util.List;

public class Test1 {
    public static void main(String[] args) {
        Account.demo(new AccountUnsafe(10000));
    }
}

class AccountUnsafe implements Account{

    private Integer balance;

    public AccountUnsafe(Integer balance) {
        this.balance = balance;
    }

    @Override
    public Integer getBalance() {
        return balance;
    }

    @Override
    public void withdraw(Integer amount) {
        balance -= amount;
    }
}

interface Account {

    // 获取余额
    Integer getBalance();

    // 取款
    void withdraw(Integer amount);

    /**
     * 方法内会启动 1000 个线程,每个线程做取款 10 元的操作
     * 如果初始余额为 10000 元,那么终止余额应当是 0 元
     */
    static void demo(Account account) {
        List<Thread> ts = new ArrayList<>();
        long start = System.nanoTime();
        for (int i = 0; i < 1000; i++) {
            ts.add(new Thread(() -> {
                account.withdraw(10);
            }));
        }
        ts.forEach(Thread::start);
        ts.forEach(t -> {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        long end = System.nanoTime();
        System.out.println("终止余额 = " + account.getBalance()
                + ";cost " + (end - start) / 1000_000 + " ms");
    }
}
// 某次运行结果

终止余额 = 180;cost 107 ms

进程已结束,退出代码 0

造成某次运行结果同预期结果不符的原因:非线程安全


6.1.1 解决思路 - 锁

package com.rui.six;

import java.util.ArrayList;
import java.util.List;

public class Test1 {
    public static void main(String[] args) {
        Account.demo(new AccountUnsafe(10000));
        Account.demo(new AccountSynchronized(10000));
    }
}

class AccountSynchronized implements Account {

    private Integer balance;

    public AccountSynchronized(Integer balance) {
        this.balance = balance;
    }

    @Override
    public synchronized Integer getBalance() {
        return balance;
    }

    @Override
    public synchronized void withdraw(Integer amount) {
        balance -= amount;
    }
}

class AccountUnsafe implements Account {

    private Integer balance;

    public AccountUnsafe(Integer balance) {
        this.balance = balance;
    }

    @Override
    public Integer getBalance() {
        return balance;
    }

    @Override
    public void withdraw(Integer amount) {
        balance -= amount;
    }
}

interface Account {

    // 获取余额
    Integer getBalance();

    // 取款
    void withdraw(Integer amount);

    /**
     * 方法内会启动 1000 个线程,每个线程做取款 10 元的操作
     * 如果初始余额为 10000 元,那么终止余额应当是 0 元
     */
    static void demo(Account account) {
        List<Thread> ts = new ArrayList<>();
        long start = System.nanoTime();
        for (int i = 0; i < 1000; i++) {
            ts.add(new Thread(() -> {
                account.withdraw(10);
            }));
        }
        ts.forEach(Thread::start);
        ts.forEach(t -> {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        long end = System.nanoTime();
        System.out.println("终止余额 = " + account.getBalance()
                + ";cost " + (end - start) / 1000_000 + " ms");
    }
}
// 某次运行结果

终止余额 = 200;cost 120 ms
终止余额 = 0;cost 75 ms

进程已结束,退出代码 0

 6.1.2 解决思路 - 无锁

本章内容【问题不大】

package com.rui.six;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

public class Test1 {
    public static void main(String[] args) {
        Account.demo(new AccountUnsafe(10000));
        Account.demo(new AccountSynchronized(10000));
        Account.demo(new AccountCas(10000));
    }
}

class AccountCas implements Account {
    private AtomicInteger balance;

    public AccountCas(Integer balance) {
        this.balance = new AtomicInteger(balance);
    }

    @Override
    public Integer getBalance() {
        return balance.get();
    }

    @Override
    public void withdraw(Integer amount) {
        while (true) {
            int prev = balance.get();
            int next = prev - amount;
            if (balance.compareAndSet(prev, next)) {
                break;
            }
        }
    }
}

class AccountSynchronized implements Account {

    private Integer balance;

    public AccountSynchronized(Integer balance) {
        this.balance = balance;
    }

    @Override
    public synchronized Integer getBalance() {
        return balance;
    }

    @Override
    public synchronized void withdraw(Integer amount) {
        balance -= amount;
    }
}

class AccountUnsafe implements Account {

    private Integer balance;

    public AccountUnsafe(Integer balance) {
        this.balance = balance;
    }

    @Override
    public Integer getBalance() {
        return balance;
    }

    @Override
    public void withdraw(Integer amount) {
        balance -= amount;
    }
}

interface Account {

    // 获取余额
    Integer getBalance();

    // 取款
    void withdraw(Integer amount);

    /**
     * 方法内会启动 1000 个线程,每个线程做取款 10 元的操作
     * 如果初始余额为 10000 元,那么终止余额应当是 0 元
     */
    static void demo(Account account) {
        List<Thread> ts = new ArrayList<>();
        long start = System.nanoTime();
        for (int i = 0; i < 1000; i++) {
            ts.add(new Thread(() -> {
                account.withdraw(10);
            }));
        }
        ts.forEach(Thread::start);
        ts.forEach(t -> {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        long end = System.nanoTime();
        System.out.println("终止余额 = " + account.getBalance()
                + ";cost " + (end - start) / 1000_000 + " ms");
    }
}
// 某次运行结果

终止余额 = 500;cost 135 ms
终止余额 = 0;cost 86 ms
终止余额 = 0;cost 59 ms

进程已结束,退出代码 0

 6.2 CAS 和 volatile

while (true) {
    int prev = balance.get();
    int next = prev - amount;
    if (balance.compareAndSet(prev, next)) {
        break;
    }
}

CAS:compareAndSet,直译 “比较并设置” 

//(线程 1 )

int prev = balance.get();  // 获取余额 100

int next = prev - amount;  // 减 10 = 90

// (线程 2 )已经修改为 90 了

balance.compareAndSet(prev, next)  // 因为100 != 90,所以 return false

// ...

int prev = balance.get();  // 获取余额 80

int next = prev - amount;  // 减 10 = 70

balance.compareAndSet(prev, next)  // 因为80 == 80,所以将余额修改为 70 并 return true

volatile 关键字对 CAS 中的 C 提供了可见性的支持


【6.1.2 解决思路 - 无锁】的某次运行结果表明,无锁的运行效率高于 synchronized 的运行效率,为什么?

在线程数小于 CPU core 数的条件下, synchronized 会发生上下文切换而无锁不会。


CAS 运用了乐观锁的思想;synchronized 运用了悲观锁的思想

CAS 适用于线程数少、多核 CPU 的情况

线程数少、多核 CPU 不等同于 线程数小于 CPU core数

多线程、单核 CPU 的情况一定会发生上下文切换

线程数多的情况可能会导致 CAS 频繁 return false


import java.util.concurrent.atomic

6.3 原子整数

AtomicBoolean、AtomicInteger、AtomicLong

以 AtomicInteger 为例

构造方法(AtomicInteger)

无参构造
package com.rui.six;

import java.util.concurrent.atomic.AtomicInteger;

public class Test2 {
    public static void main(String[] args) {

        AtomicInteger value = new AtomicInteger();

        System.out.println(value.get());
    }
}
// 运行结果

0

进程已结束,退出代码 0
有参构造
package com.rui.six;

import java.util.concurrent.atomic.AtomicInteger;

public class Test2 {
    public static void main(String[] args) {

        AtomicInteger value = new AtomicInteger(5);

        System.out.println(value.get());
    }
}
// 运行代码

5

进程已结束,退出代码 0

incrementAndGet

value.incrementAndGet() 等同于 ++value

package com.rui.six;

import java.util.concurrent.atomic.AtomicInteger;

public class Test2 {
    public static void main(String[] args) {

        AtomicInteger value = new AtomicInteger(5);

        System.out.println(value.incrementAndGet());
    }
}
// 运行结果

6

进程已结束,退出代码 0

getAndIncrement

value.getAndIncrement() 等同于 value++

package com.rui.six;

import java.util.concurrent.atomic.AtomicInteger;

public class Test2 {
    public static void main(String[] args) {

        AtomicInteger value = new AtomicInteger(5);

        System.out.println(value.getAndIncrement());

        System.out.println(value.get());
    }
}
// 运行结果

5
6

进程已结束,退出代码 0

decrementAndGet

value.decrementAndGet() 等同于 --value

getAndDecrement

value.getAndDecrement() 等同于 value--

addAndGet

package com.rui.six;

import java.util.concurrent.atomic.AtomicInteger;

public class Test2 {
    public static void main(String[] args) {

        AtomicInteger value = new AtomicInteger(5);

        System.out.println(value.addAndGet(-4));  // 1 <- 5+(-4)=1
    }
}
// 运行结果

1

进程已结束,退出代码 0

【6.1.2 解决思路 - 无锁】优化 

package com.rui.six;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

public class Test1 {
    public static void main(String[] args) {
        Account.demo(new AccountCas(10000));
    }
}

class AccountCas implements Account {
    private AtomicInteger balance;

    public AccountCas(Integer balance) {
        this.balance = new AtomicInteger(balance);
    }

    @Override
    public Integer getBalance() {
        return balance.get();
    }

    @Override
    public void withdraw(Integer amount) {
        balance.addAndGet(-amount);
    }
}

interface Account {

    // 获取余额
    Integer getBalance();

    // 取款
    void withdraw(Integer amount);

    /**
     * 方法内会启动 1000 个线程,每个线程做取款 10 元的操作
     * 如果初始余额为 10000 元,那么终止余额应当是 0 元
     */
    static void demo(Account account) {
        List<Thread> ts = new ArrayList<>();
        long start = System.nanoTime();
        for (int i = 0; i < 1000; i++) {
            ts.add(new Thread(() -> {
                account.withdraw(10);
            }));
        }
        ts.forEach(Thread::start);
        ts.forEach(t -> {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        long end = System.nanoTime();
        System.out.println("终止余额 = " + account.getBalance()
                + ";cost " + (end - start) / 1000_000 + " ms");
    }
}
// 运行结果

终止余额 = 0;cost 96 ms

进程已结束,退出代码 0

getAndAdd

package com.rui.six;

import java.util.concurrent.atomic.AtomicInteger;

public class Test2 {
    public static void main(String[] args) {

        AtomicInteger value = new AtomicInteger(5);

        System.out.println(value.getAndAdd(5));

        System.out.println(value.get());
    }
}
// 运行结果

5
10

进程已结束,退出代码 0

updateAndGet

package com.rui.six;

import java.util.concurrent.atomic.AtomicInteger;

public class Test2 {
    public static void main(String[] args) {

        AtomicInteger value = new AtomicInteger(5);

        System.out.println(value.updateAndGet(x -> x * -1));  // -5 <- 5*(-1)=-5
    }
}
// 运行结果

-5

进程已结束,退出代码 0

getAndUpdate

package com.rui.six;

import java.util.concurrent.atomic.AtomicInteger;

public class Test2 {
    public static void main(String[] args) {

        AtomicInteger value = new AtomicInteger(5);

        System.out.println(value.getAndUpdate(x -> x + 2));

        System.out.println(value.get());
    }
}
// 运行结果

5
7

进程已结束,退出代码 0
package com.rui.six;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.IntUnaryOperator;

public class Test3 {
    public static void main(String[] args) {
        AtomicInteger value = new AtomicInteger(5);

        System.out.println(getAndUpdate(value, x -> x * 2));

        System.out.println(value.get());
    }

    public static int getAndUpdate(AtomicInteger value, IntUnaryOperator operator) {
        while (true) {
            int prev = value.get();
            int next = operator.applyAsInt(prev);
            if (value.compareAndSet(prev, next)) {
                return prev;
            }
        }
    }
}
// 运行结果

5
10

进程已结束,退出代码 0

6.4 原子引用

AtomicReference、AtomicMarkableReference、AtomicStampedReference

AtomicReference

package com.rui.six;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

public class Test4 {
    public static void main(String[] args) {
        Account4.demo(new AccountCas4(new BigDecimal("10000")));
    }
}

class AccountCas4 implements Account4 {
    private AtomicReference<BigDecimal> balance;

    public AccountCas4(BigDecimal balance) {
        this.balance = new AtomicReference<>(balance);
    }

    @Override
    public BigDecimal getBalance() {
        return balance.get();
    }

    @Override
    public void withdraw(BigDecimal amount) {
        while (true) {
            BigDecimal prev = balance.get();
            BigDecimal next = prev.subtract(amount);
            if (balance.compareAndSet(prev, next)) {
                break;
            }
        }
    }
}

interface Account4 {

    // 获取余额
    BigDecimal getBalance();

    // 取款
    void withdraw(BigDecimal amount);

    /**
     * 方法内会启动 1000 个线程,每个线程做取款 10 元的操作
     * 如果初始余额为 10000 元,那么终止余额应当是 0 元
     */
    static void demo(Account4 account) {
        List<Thread> ts = new ArrayList<>();
        long start = System.nanoTime();
        for (int i = 0; i < 1000; i++) {
            ts.add(new Thread(() -> {
                account.withdraw(BigDecimal.TEN);
            }));
        }
        ts.forEach(Thread::start);
        ts.forEach(t -> {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        long end = System.nanoTime();
        System.out.println("终止余额 = " + account.getBalance()
                + ";cost " + (end - start) / 1000_000 + " ms");
    }
}
// 运行结果

终止余额 = 0;cost 116 ms

进程已结束,退出代码 0

package com.rui.six;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.atomic.AtomicReference;

@Slf4j(topic = "c.Test5")
public class Test5 {
    static AtomicReference<String> value = new AtomicReference<>("A");

    public static void main(String[] args) throws InterruptedException {
        log.debug("main begin...");
        other();
        Thread.sleep(1000);
        log.debug("A -> C : {}", value.compareAndSet(value.get(), "C"));
    }

    public static void other() throws InterruptedException {
        new Thread(() -> {
            log.debug("t1 begin...");
            log.debug("A -> B : {}", value.compareAndSet(value.get(), "B"));
        }, "t1").start();
        Thread.sleep(500);
        new Thread(() -> {
            log.debug("t2 begin...");
            log.debug("B -> A : {}", value.compareAndSet(value.get(), "A"));
        }, "t2").start();
    }
}
// 运行结果

11:46:15 [main] c.Test5 - main begin...
11:46:15 [t1] c.Test5 - t1 begin...
11:46:15 [t1] c.Test5 - A -> B : true
11:46:16 [t2] c.Test5 - t2 begin...
11:46:16 [t2] c.Test5 - B -> A : true
11:46:17 [main] c.Test5 - A -> C : true

进程已结束,退出代码 0

上述代码中,对 value 的修改(ABA 问题)未能被检测到,那么如何检测到这种修改呢?

AtomicStampedReference

AtomicStampedReference

package com.rui.six;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.atomic.AtomicStampedReference;

@Slf4j(topic = "c.Test5")
public class Test6 {
    static AtomicStampedReference<String> value = new AtomicStampedReference<>("A", 0);

    public static void main(String[] args) throws InterruptedException {
        log.debug("main begin...");
        int stamp = value.getStamp();
        other();
        Thread.sleep(1000);
        log.debug("stamp = {}", stamp);
        log.debug("A -> C : {}", value.compareAndSet(value.getReference(), "C", stamp, stamp + 1));
    }

    public static void other() throws InterruptedException {
        new Thread(() -> {
            log.debug("t1 begin...");
            log.debug("A -> B : {}", value.compareAndSet(value.getReference(), "B", value.getStamp(), value.getStamp() + 1));
        }, "t1").start();
        Thread.sleep(500);
        new Thread(() -> {
            log.debug("t2 begin...");
            log.debug("B -> A : {}", value.compareAndSet(value.getReference(), "A", value.getStamp(), value.getStamp() + 1));
        }, "t2").start();
    }
}
// 运行结果

11:55:23 [main] c.Test5 - main begin...
11:55:23 [t1] c.Test5 - t1 begin...
11:55:23 [t1] c.Test5 - A -> B : true
11:55:23 [t2] c.Test5 - t2 begin...
11:55:23 [t2] c.Test5 - B -> A : true
11:55:24 [main] c.Test5 - stamp = 0
11:55:24 [main] c.Test5 - A -> C : false

进程已结束,退出代码 0

AtomicMarkableReference

package com.rui.six;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.atomic.AtomicMarkableReference;
import java.util.concurrent.atomic.AtomicReference;

@Slf4j(topic = "c.Test7")
public class Test7 {
    static AtomicMarkableReference<String> amr = new AtomicMarkableReference<>("垃圾溢出", true);
    public static void main(String[] args) throws InterruptedException {
        other();
        Thread.sleep(1000);
        log.debug("T/F?{}",amr.compareAndSet(amr.getReference(),"清理垃圾",true,false));
    }

    public static void other() {
        new Thread(() -> {
            log.debug("T/F?{}",amr.compareAndSet(amr.getReference(),"清理垃圾",true,false));
            log.debug("{}",amr.getReference());
        },"保洁阿姨 1 号").start();

        new Thread(() -> {
            log.debug("T/F?{}",amr.compareAndSet(amr.getReference(),"垃圾溢出",true,false));
            log.debug("{}",amr.getReference());
        },"保洁阿姨 2 号").start();
    }
}

class GarbageBag {
    private String garbageBag;

    public GarbageBag(String garbageBag) {
        this.garbageBag = garbageBag;
    }

    public String getGarbageBag() {
        return garbageBag;
    }

    @Override
    public String toString() {
        return "GarbageBag{" +
                "garbageBag='" + garbageBag + '\'' +
                '}';
    }
}
// 运行结果

12:06:27 [保洁阿姨 1 号] c.Test7 - T/F?true
12:06:27 [保洁阿姨 2 号] c.Test7 - T/F?false
12:06:27 [保洁阿姨 2 号] c.Test7 - 清理垃圾
12:06:27 [保洁阿姨 1 号] c.Test7 - 清理垃圾
12:06:28 [main] c.Test7 - T/F?false

进程已结束,退出代码 0

6.5 原子数组

AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray

非线程安全

package com.rui.six;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.*;

public class Test8 {
    public static void main(String[] args) {
        demo(
                () -> new int[10],
                (array) -> array.length,
                (array, index) -> array[index]++,
                (array) -> System.out.println(Arrays.toString(array))

        );
    }

    /**
     * 参数1,提供数组、可以是线程不安全数组或线程安全数组
     * 参数2,获取数组长度的方法
     * 参数3,自增方法,回传 array、index
     * 参数4,打印数组的方法
     */
    // Supplier 提供者 无中生有 () -> 结果
    // Function 函数 一个参数一个结果 (参数) -> 结果,BiFunction (参数1,参数2) -> 结果
    // Consumer 消费者 一个参数没结果 (参数) -> void,BiConsumer (参数1,参数2) -> void
    private static <T> void demo(
            Supplier<T> arraySupplier,
            Function<T, Integer> lengthFun,
            BiConsumer<T, Integer> putConsumer,
            Consumer<T> printConsumer) {
        List<Thread> list = new ArrayList<>();
        T array = arraySupplier.get();
        int length = lengthFun.apply(array);
        for (int i = 0; i < length; i++) {
            // 每个线程对数组做 10000 次操作
            list.add(new Thread(() -> {
                for (int j = 0; j < 10000; j++) {
                    putConsumer.accept(array, j % length);
                }
            }));
        }
        list.forEach(t -> t.start()); // 启动所有线程
        list.forEach(t -> {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }); // 等所有线程结束
        printConsumer.accept(array);
    }
}
// 某次运行结果

[9496, 9462, 9530, 9506, 9486, 9509, 9522, 9494, 9447, 9483]

进程已结束,退出代码 0

线程安全 - 以 AtomicIntegerArray 为例

package com.rui.six;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicIntegerArray;
import java.util.function.*;

public class Test8 {
    public static void main(String[] args) {
        demo(
                () -> new int[10],
                (array) -> array.length,
                (array, index) -> array[index]++,
                (array) -> System.out.println(Arrays.toString(array))

        );

        demo(
                () -> new AtomicIntegerArray(10),
                (array) -> array.length(),
                (array, index) -> array.getAndIncrement(index),
                (array) -> System.out.println(array)
        );
    }

    /**
     * 参数1,提供数组、可以是线程不安全数组或线程安全数组
     * 参数2,获取数组长度的方法
     * 参数3,自增方法,回传 array、index
     * 参数4,打印数组的方法
     */
    // Supplier 提供者 无中生有 () -> 结果
    // Function 函数 一个参数一个结果 (参数) -> 结果,BiFunction (参数1,参数2) -> 结果
    // Consumer 消费者 一个参数没结果 (参数) -> void,BiConsumer (参数1,参数2) -> void
    private static <T> void demo(
            Supplier<T> arraySupplier,
            Function<T, Integer> lengthFun,
            BiConsumer<T, Integer> putConsumer,
            Consumer<T> printConsumer) {
        List<Thread> list = new ArrayList<>();
        T array = arraySupplier.get();
        int length = lengthFun.apply(array);
        for (int i = 0; i < length; i++) {
            // 每个线程对数组做 10000 次操作
            list.add(new Thread(() -> {
                for (int j = 0; j < 10000; j++) {
                    putConsumer.accept(array, j % length);
                }
            }));
        }
        list.forEach(t -> t.start()); // 启动所有线程
        list.forEach(t -> {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }); // 等所有线程结束
        printConsumer.accept(array);
    }
}
// 某次运行结果

[9076, 9056, 9086, 9076, 9036, 9048, 9810, 9772, 9794, 9806]
[10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000]

进程已结束,退出代码 0

6.7 字段更新器

AtomicReferenceFieldUpdater

修改成员变量

package com.rui.six;

import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

public class Test9 {
    public static void main(String[] args) {
        Student stu = new Student();
        AtomicReferenceFieldUpdater arfu = AtomicReferenceFieldUpdater.newUpdater(Student.class, String.class, "name");
        System.out.println(arfu.compareAndSet(stu, null, "张三"));
        System.out.println(stu);
    }
}

class Student {
    public volatile String name;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                '}';
    }
}
// 运行结果

true
Student{name='张三'}

进程已结束,退出代码 0

 6.8 原子累加器

package com.rui.six;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;
import java.util.function.Consumer;
import java.util.function.Supplier;

public class Test10 {
    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            demo(
                    () -> new AtomicLong(),
                    (adder) -> adder.incrementAndGet()
            );
        }

        System.out.println("================== 一条华丽的分割线 ==================");

        for (int i = 0; i < 5; i++) {
            demo(
                    () -> new LongAdder(),
                    (adder) -> adder.increment()
            );
        }

    }

    private static <T> void demo(Supplier<T> adderSupplier, Consumer<T> action) {
        T adder = adderSupplier.get();
        long start = System.nanoTime();
        List<Thread> list = new ArrayList<>();
        // 40 个线程,每个线程累加 50 W
        for (int i = 0; i < 40; i++) {
            list.add(new Thread(() -> {
                for (int j = 0; j < 500000; j++) {
                    action.accept(adder);
                }
            }));
        }
        list.forEach(t -> t.start());
        list.forEach(t -> {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        long end = System.nanoTime();
        System.out.println(adder + ",cost:" + (end - start) / 1000_000);
    }
}
// 某次运行结果

20000000,cost:180
20000000,cost:165
20000000,cost:163
20000000,cost:161
20000000,cost:161
================== 一条华丽的分割线 ==================
20000000,cost:18
20000000,cost:9
20000000,cost:9
20000000,cost:25
20000000,cost:18

进程已结束,退出代码 0

说些废话

本篇文章为博主日常学习记录,故而会概率性地存在各种错误,若您在浏览过程中发现一些,请在评论区指正,望我们共同进步,谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值