并发编程(下)

并发编程(下)

1.共享模型之内存

1.1 java内存模型

image-20220521223235398

1.2 可见性

image-20220521224754033

  • 原因分析

    image-20220521224827221

image-20220521224847005

image-20220521224910648

  • 一个线程对主存对数据进行修改 对另外一个线程是不可见的

  • 解决方法 使用volatile

    image-20220521225404248

  • 可见性 vs 原子性

image-20220521230917522

image-20220521231005690

  • 因为println加了synchronized

    image-20220521231305209

1.3 同步模式之Baliking

image-20220521233628697

@Slf4j(topic = "c.test2")
public class Test2 {
    public static void main(String[] args) {
        TwoPhaseTermination t1 = new TwoPhaseTermination();
        // 重复调用2次start方法 不产生2个线程
        t1.start();
        t1.start();
        Sleeper.sleep(4);
        log.debug("停止监控线程");
        t1.stop();
    }
}

@Slf4j(topic = "c.TwoPhaseTermination")
class TwoPhaseTermination {
    // 监控线程
    private Thread thread;

    private volatile boolean stop = false;
    // 用于判断是否执行过start方法
    private boolean starting = false;

    public void start() {
        synchronized (this) {
            if (starting) {
                return;
            }
            starting = true;
        }
        thread = new Thread(() -> {
            while (true) {
                if (stop) {
                    log.debug("料理后事");
                    break;
                }
                try {
                    Thread.sleep(1000);
                    log.debug("执行监控记录");
                } catch (Exception e) {

                }
            }
        });

        thread.start();
    }


    public void stop() {
        stop = true;
        thread.interrupt();
    }
}

1.4 指令重排序

  • 有序性

    image-20220522094557877

image-20220522094620982

  • 指令重排序优化

    image-20220522095505851

image-20220522095530245

image-20220522095915644

  • 结论:在不改变程序结果的前提下,这些指令的各个阶段可以通过重排序和组合来实现指令级并行,指令重排的前提是,重排指令不能影响结果

1.5 volatile原理

image-20220522102621854

1.如何保证可见性

image-20220522102811438

2.如何保证有序性

image-20220522103337968

  • volatile不能保证原子性

    image-20220522103439964

3.double-checked-locking
  • 问题

    image-20220522110148136

image-20220522110238446

image-20220522110326529

image-20220522110403624

image-20220522110542317

image-20220522110646414

  • 解决
@Slf4j(topic = "c.test3")
public class Test3 {
    public Test3() {
    }
    // volatile 防止指令重排序
    private static volatile Test3 INSTANCE = null;
    
    public static Test3 getInstance() {
        // 首次判断为不为空
        if (INSTANCE == null) {
            synchronized (Test3.class) {
                // t1 t2 两个线程 只能有一个线程进入代码块 去初始化对象
                if (INSTANCE == null) {
                    INSTANCE = new Test3();
                }
            }
        }
        return INSTANCE;
    }
}
4.happens-before

image-20220522111029133

image-20220522111100590

image-20220522111208783

image-20220522111246734

image-20220522111354826

image-20220522111415555

image-20220522111753735

2.共享模型之无锁

1.CAS

  • 无锁实现对共享变量操作
@Slf4j(topic = "c.test4")
public class Test4 {
    public static void main(String[] args) {
        AccountCas cas = new AccountCas(10000);
        Account.demo(cas);
    }
}

class AccountCas implements Account {

    private AtomicInteger atomicInteger;

    public AccountCas(int a) {
        AtomicInteger c = new AtomicInteger(a);
        this.atomicInteger = c;
    }

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

    @Override
    public void withdraw(Integer account) {
        while (true) {
            int pre = atomicInteger.get();
            // cas 自旋操作
            int update = pre - account;
            if (atomicInteger.compareAndSet(pre, update)) {
                break;
            }
        }
    }
}

interface Account {
    // 获取余额
    Integer getBalance();

    // 取款
    void withdraw(Integer account);

    /**
     * 启动1000个线程 进行取款操作
     *
     * @param account
     */
    static void demo(Account account) {
        List<Thread> list = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            list.add(new Thread(() -> {
                account.withdraw(10);
            }));
        }
        // 耗时
        long startTime = System.currentTimeMillis();
        list.forEach(Thread::start);
        // 等待全部线程结束
        list.forEach(thread -> {
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        long endTime = System.currentTimeMillis();
        System.out.println(account.getBalance() + "cost:" + "耗时:" + (endTime - startTime) + "ms");
    }
}
  • cas工作原理

image-20220522134725981

image-20220522134755824

image-20220522135227021

  • 为什么无锁效率高

image-20220522135627358

  • CAS的特点

image-20220522140222807

2 .原子整数

  • AtomicInteger

image-20220522143639894

3. 原子引用

@Slf4j(topic = "c.test5")
public class Test5 {

    public static void main(String[] args) {
        // BigDecimal赋值必须是字符串 如果是浮点数还是会有精度损失
        AccountReferenceImpl reference = new AccountReferenceImpl(new BigDecimal("10000"));
        AccountReference.demo(reference);
    }
}

class AccountReferenceImpl implements AccountReference {

    private AtomicReference<BigDecimal> atomicReference;

    public AccountReferenceImpl(BigDecimal bigDecimal) {
        AtomicReference<BigDecimal> atomicReference = new AtomicReference<>(bigDecimal);
        this.atomicReference = atomicReference;
    }

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

    @Override
    public void withdraw(BigDecimal account) {
        while (true) {
            BigDecimal pre = atomicReference.get();
            // cas 自旋操作
            BigDecimal update = pre.subtract(account);
            if (atomicReference.compareAndSet(pre, update)) {
                break;
            }
        }
    }
}

interface AccountReference {
    // 获取余额
    BigDecimal getBalance();

    // 取款
    void withdraw(BigDecimal account);

    /**
     * 启动1000个线程 进行取款操作
     *
     * @param account
     */
    static void demo(AccountReference account) {
        List<Thread> list = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            list.add(new Thread(() -> {
                account.withdraw(BigDecimal.TEN);
            }));
        }
        // 耗时
        long startTime = System.currentTimeMillis();
        list.forEach(Thread::start);
        // 等待全部线程结束
        list.forEach(thread -> {
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        long endTime = System.currentTimeMillis();
        System.out.println(account.getBalance() + "cost:" + "耗时:" + (endTime - startTime) + "ms");
    }
}
  • ABA问题

    @Slf4j(topic = "c.test6")
    public class Test6 {
        private static AtomicReference<String> ref = new AtomicReference<>("A");
    
        public static void main(String[] args) {
            log.debug("main start..");
            String pre = ref.get();
            other();
            Sleeper.sleep(2);
            log.debug("changeA->C {}", ref.compareAndSet(pre, "C"));
        }
    
        public static void other() {
            new Thread(() -> {
                log.debug("changeA->B {}", ref.compareAndSet(ref.get(), "B"));
            }, "t1").start();
            Sleeper.sleep(1);
            new Thread(() -> {
                log.debug("changeB->A {}", ref.compareAndSet(ref.get(), "A"));
            }, "t2").start();
        }
    }
    

    image-20220522151727493

  • 所谓ABA问题也就是说主线程要修改的值 被其他线程先修改了 不过其它线程又改成了主线程最开始的值,但这对于主线程是无感知的

  • 解决 使用AtomicStampedReference加版本号的方式 来判断是否被其它线程修改过

    @Slf4j(topic = "c.test6")
    public class Test6 {
        private static AtomicStampedReference<String> ref = new AtomicStampedReference<>("A", 0);
    
        public static void main(String[] args) {
            log.debug("main start..");
            String pre = ref.getReference();
            int stamp = ref.getStamp();
            log.debug("main版本号为:{}", stamp);
            other();
            Sleeper.sleep(2);
            log.debug("main休眠后 版本号为:{}",ref.getStamp());
            log.debug("changeA->C {}", ref.compareAndSet(pre, "C", stamp, stamp + 1));
        }
    
        public static void other() {
            new Thread(() -> {
                log.debug("changeA->B {}", ref.compareAndSet(ref.getReference(), "B", ref.getStamp(), ref.getStamp() + 1));
                log.debug("t1修改后版本号为:{}", ref.getStamp());
            }, "t1").start();
            Sleeper.sleep(1);
            new Thread(() -> {
                log.debug("changeB->A {}", ref.compareAndSet(ref.getReference(), "A", ref.getStamp(), ref.getStamp() + 1));
                log.debug("t2修改后版本号为:{}", ref.getStamp());
            }, "t2").start();
        }
    }
    

    image-20220522154246776

  • 需求 我不关心版本号有没有改变 我只关心值有没有被其它线程修改过?

    @Slf4j(topic = "c.test7")
    public class Test7 {
        public static void main(String[] args) {
            AtomicMarkableReference<GarbageBag> reference = new AtomicMarkableReference<>(new GarbageBag("装满了垃圾"), true);
            log.debug("start...");
            GarbageBag pre = reference.getReference();
            log.debug(pre.toString());
    
            new Thread(() -> {
                log.debug("t1线程想更换垃圾袋子");
                // expectedMark—期望值
                // newMark -标记的新值
                boolean andSet = reference.compareAndSet(pre, new GarbageBag("t1空垃圾袋子"), true, true);
                log.debug("t1线程更换成功了没:{}", andSet);
            }, "t1").start();
    
            Sleeper.sleep(1);
            log.debug("想换一个新的垃圾袋");
            boolean result = reference.compareAndSet(pre, new GarbageBag("空垃圾袋"), true, true);
            log.debug("换成功了没:{}", result);
            log.debug(reference.getReference().toString());
        }
    
    }
    
    class GarbageBag {
        private String name;
    
        public GarbageBag(String name) {
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    
        @Override
        public String toString() {
            return "垃圾袋{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }
    

4.原子数组

@Slf4j(topic = "c.test8")
public class Test8 {
    public static void main(String[] args) {
        demo(
                () -> new int[10],
                (arr) -> arr.length,
                (arr, index) -> arr[index]++,
                (arr) -> System.out.println(Arrays.toString(arr))
        );
    }

    // 参数1提供数组
    // 参数2数组长度
    // 自增方法
    // 打印
    private static <T> void demo(Supplier<T> arrSupplier,
                                 Function<T, Integer> arrFunction,
                                 BiConsumer<T, Integer> arrBiConsumer,
                                 Consumer<T> arrConsumer
    ) {
        List<Thread> list = new ArrayList<>();
        T arr = arrSupplier.get();
        // 获取数组长度
        Integer arrLength = arrFunction.apply(arr);
        for (int i = 0; i < arrLength; i++) {
            list.add(new Thread(() -> {
                for (int j = 0; j < 1000; j++) {
                    arrBiConsumer.accept(arr, j % arrLength);
                }
            }));
        }
        list.forEach(Thread::start);
        list.forEach(t -> {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        arrConsumer.accept(arr);
    }
}

image-20220522165213643

  • 多线程下数组元素是没有安全性的
  • 解决使用AtomicIntegerArray
            demo(
                    () -> new AtomicIntegerArray(10),
                    (arr) -> arr.length(),
                    (arr, index) -> arr.incrementAndGet(index),
                    (arr) -> System.out.println(arr)
            );

image-20220522165637412

5.字段更新器

image-20220522170051475

@Slf4j(topic = "c.test9")
public class Test9 {
    public static void main(String[] args) {
        User user = new User();
        AtomicReferenceFieldUpdater atomicReferenceFieldUpdater = AtomicReferenceFieldUpdater
                .newUpdater(User.class, String.class, "name");

        System.out.println(atomicReferenceFieldUpdater.compareAndSet(user, null, "张三"));
        System.out.println(user);

    }
}

class User {
    // cas操作需要变量被volatile修饰
    volatile String name;

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }
}

6.原子累加器

  • LongAdder
@Slf4j(topic = "c.test10")
public class Test10 {
    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            demo(() -> new AtomicLong(0), (arr) -> arr.incrementAndGet());
        }

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

    private static <T> void demo(Supplier<T> arrSupplier,
                                 Consumer<T> arrFunction
    ) {
        List<Thread> list = new ArrayList<>();
        T arr = arrSupplier.get();
        // 获取数组长度
        for (int i = 0; i < 4; i++) {
            list.add(new Thread(() -> {
                for (int j = 0; j < 50000; j++) {
                    arrFunction.accept(arr);
                }
            }));
        }
        long startTime = System.currentTimeMillis();
        list.forEach(Thread::start);
        list.forEach(t -> {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        long endTime = System.currentTimeMillis() - startTime;
        System.out.println(arr + "cost:" + endTime);
    }
}

image-20220522193446536

image-20220522193531180

源码之LongAdder

image-20220522193808978

image-20220522194639560

image-20220528221605004

image-20220522194949645

image-20220528221759729

image-20220522201229281

  • add方法

image-20220522201750514

image-20220522201805580

  • longAccumulate方法

    image-20220522204814329

image-20220522204724198

  • cells数组存在 但线程的cell对象没创建

    image-20220522205738985

    image-20220522205635645

  • 最后一种情况 cells 和cell都存在 进行cas操作

    image-20220522210547153

    image-20220522210418862

  • sum求和

    image-20220522210704295

6.Unsafe

image-20220522211023024

  • 原子整数底层也是用unsafe实现的

    @Slf4j(topic = "c.test12")
    public class Test12 {
        public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
            Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
            // 设置允许访问私有变量
            theUnsafe.setAccessible(true);
            // 因为unsafe被修饰static所以同属于类  不同属于对象  所有不需要传递对象
            Unsafe unsafe = (Unsafe) theUnsafe.get(null);
    
            // unsafe实现cas操作
            Teacher thread = new Teacher();
            // 获取id和name的offset
            long id = unsafe.objectFieldOffset(Teacher.class.getDeclaredField("id"));
            long name = unsafe.objectFieldOffset(Teacher.class.getDeclaredField("name"));
            unsafe.compareAndSwapInt(thread, id, 0, 1);
            unsafe.compareAndSwapObject(thread, name, null, "sb");
            System.out.println(thread);
        }
    }
    
    @Data
    class Teacher {
        public volatile int id;
        public volatile String name;
    
    }
    
  • 使用unsafe实现MyAtomicIntger

    @Slf4j(topic = "c.test13")
    public class Test13 {
        public static void main(String[] args) {
            Account.demo(new MyAtomicInt(10000));
        }
    
    }
    
    class MyAtomicInt implements Account {
        private volatile int value;
        private static final long VALUEOFFSET;
        private static final Unsafe UNSAFE;
    
        static {
            try {
                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
                theUnsafe.setAccessible(true);
                // 因为unsafe被修饰static所以同属于类  不同属于对象  所有不需要传递对象
                UNSAFE = (Unsafe) theUnsafe.get(null);
    
                VALUEOFFSET = UNSAFE.objectFieldOffset(MyAtomicInt.class.getDeclaredField("value"));
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException();
            }
        }
    
        public int getValue() {
            return value;
        }
    
    
        public MyAtomicInt(int value) {
            this.value = value;
        }
    
    
        public void decrement(int account) {
            while (true) {
                int pre = this.value;
                int update = pre - account;
                if (UNSAFE.compareAndSwapInt(this, VALUEOFFSET, pre, update)) {
                    break;
                }
            }
        }
    
        @Override
        public Integer getBalance() {
            return getValue();
        }
    
        @Override
        public void withdraw(Integer account) {
            decrement(account);
        }
    }
    

3.共享模型之不可变

  • 由于simpledatefomat不是线程安全的

    image-20220522222347423

1.不可变类设计

image-20220522223223938

  • final作用

    属性使用了final保证改属性是只读的,不能修改

    保证了类中的方法不被覆盖,反正子类无意修改破坏不可变性

  • 保护性拷贝

    final只能保证数组类型的引用不被修改,那如果我修改数组里面的值呢?看看string是怎么做的

    image-20220522223554633

2.享元模式
  • 为了解决保护性拷贝每次创建新对象而占用内存的情况image-20220522224439212

  • 体现

    image-20220522224619941

3.实现自定义线程池

image-20220523232026339

@Slf4j(topic = "c.test14")
public class Test14 {
    public static void main(String[] args) {
        Pool pool = new Pool(2);
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                Connection borrow = pool.borrow();
                Sleeper.sleep(1);
                pool.free(borrow);
            }).start();
        }
    }
}

@Slf4j(topic = "c.pool")
class Pool {
    private int poolSize;

    // 连接对象数组
    private Connection[] connections;

    // 数组表示连接池状态 0空闲
    private AtomicIntegerArray status;

    public Pool(int poolSize) {
        this.poolSize = poolSize;
        this.connections = new Connection[poolSize];
        this.status = new AtomicIntegerArray(new int[poolSize]);
        for (int i = 0; i < connections.length; i++) {
            connections[i] = new MockConnection("连接" + i);
        }
    }

    // 获取连接
    public Connection borrow() {
        while (true) {
            for (int i = 0; i < poolSize; i++) {
                if (status.get(i) == 0) {
                    if (status.compareAndSet(i, 0, 1)) {
                        log.debug("borrow:{}", connections[i]);
                        return connections[i];
                    }
                }
            }
            synchronized (this) {
                try {
                    log.debug("wait...");
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    // 归还连接
    public void free(Connection connection) {
        for (int i = 0; i < poolSize; i++) {
            if (connections[i] == connection) {
                status.set(i, 0);
                synchronized (this) {
                    log.debug("free:{}", connection);
                    this.notifyAll();
                }
                break;
            }
        }
    }
}

class MockConnection implements Connection {
    private String name;

    public MockConnection(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "MockConnection{" +
                "name='" + name + '\'' +
                '}';
    }
}
4.final原理

image-20220523235024180

`

  • final获取变量的原理

image-20220523235743498

UseFinal1类中会将A变量复制一份到自已的栈内存中

image-20220528221943653

如果没加final会去TestFinal类中去找A变量,走的是共享内存

4.自定义线程池

image-20220524230738109

4.1 自定义阻塞队列
class BlockQueue<T> {
    private Deque<T> deque = new ArrayDeque<>();
    // 锁
    private ReentrantLock lock = new ReentrantLock();
    // 生产者条件变量
    private Condition fullWaitSet = lock.newCondition();
    // 消费者条件变量
    private Condition emptyWaitSet = lock.newCondition();
    // 容量
    private int capacity;

    public T poll(long time, TimeUnit unit) {
        lock.lock();
        long nanos = unit.toNanos(time);
        try {
            while (deque.isEmpty()) {
                try {
                    if (nanos <= 0) {
                        return null;     // 防止虚假唤醒
                    }
                    nanos = emptyWaitSet.awaitNanos(nanos);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            T t = deque.removeFirst();
            fullWaitSet.signal();
            return t;
        } finally {
            lock.unlock();
        }
    }

    // 阻塞获取
    public T task() {
        lock.lock();
        try {
            while (deque.isEmpty()) {
                try {
                    emptyWaitSet.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            T t = deque.removeFirst();
            fullWaitSet.signal();
            return t;
        } finally {
            lock.unlock();
        }
    }

    // 阻塞添加
    public void put(T element) {
        lock.lock();
        try {
            while (deque.size() == capacity) {
                try {
                    fullWaitSet.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            deque.addLast(element);
            emptyWaitSet.signal();
        } finally {
            lock.unlock();
        }
    }

    // 获取队列大小
    public int size() {
        lock.lock();
        try {
            return deque.size();
        } finally {
            lock.unlock();
        }
    }
}
4.2 ThreadPoolExecutor

image-20220526194200873

1.线程池状态

image-20220526194611448

2.构造方法

image-20220526195536960

image-20220526200821279

4.3 创建一个固定线程的线程池 Executors.newFixedThreadPool()
@Slf4j(topic = "c.test2")
public class Test2 {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        executorService.execute(() -> {
            log.debug("1");
        });
        executorService.execute(() -> {
            log.debug("2");
        });
        executorService.execute(() -> {
            log.debug("3");
        });
    }
}

image-20220526203112420

image-20220526202839728

  • 可以看到newFixedThreadPool方法中 生存时间为0 也就是说创建的线程池不会拥有救急线程 只会有核心线程,就算没有任务时也不会一直运行
4.4 带缓冲功能的线程池 Executors.newCachedThreadPool()

image-20220526203655724

@Slf4j(topic = "c.test3")
public class Test3 {
    public static void main(String[] args) {
        SynchronousQueue<Integer> queue = new SynchronousQueue<>();
        new Thread(() -> {
            try {
                log.debug("put:{}", 1);
                queue.put(1);
                log.debug("putted:{}", 1);
                log.debug("put:{}", 2);
                queue.put(2);
                log.debug("putted:{}", 2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        Sleeper.sleep(1);

        new Thread(() -> {
            try {
                log.debug("task:{}", 1);
                queue.take();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        Sleeper.sleep(1);
        new Thread(() -> {
            try {
                log.debug("task:{}", 2);
                queue.take();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

image-20220526204249408

4.5 单线程线程池 Executors.newSingleThreadExecutor()

image-20220526211003454

@Slf4j(topic = "c.test4")
public class Test4 {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        executorService.execute(() -> {
            log.debug("by/zero");
            int i = 1 / 0;
        });
        Sleeper.sleep(1);
        executorService.execute(() -> {
            log.debug("2");
        });
        Sleeper.sleep(1);
        executorService.execute(() -> {
            log.debug("3");
        });
    }
}

image-20220526211150698

  • 可以看到 当线程1发生异常后 会从线程池创建一个新的线程强执行其它任务
5.提交任务

image-20220526211301713

@Slf4j(topic = "c.test5")
public class Test5 {
    public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
        ExecutorService executorService = Executors.newFixedThreadPool(1);
        Future<String> future = executorService.submit(new Callable<String>() {
            @Override
            public String call() throws Exception {
                log.debug("running...");
                Sleeper.sleep(3);
                return "Ok";
            }
        });

        String s = future.get();
        log.debug("result:{}",s);
    }
}
@Slf4j(topic = "c.test6")
public class Test6 {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        List<Future<Object>> futureList = executorService.invokeAll(Arrays.asList(
                () -> {
                    log.debug("start ....1");
                    Sleeper.sleep(2);
                    return "1";
                },
                () -> {
                    log.debug("start ....2");
                    Sleeper.sleep(2);
                    return "2";
                },
                () -> {
                    log.debug("start ....3");
                    Sleeper.sleep(3);
                    return "3";
                }
        ));

        futureList.forEach(future -> {
            try {
                String result = (String) future.get();
                log.debug("result:{}", result);
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        });
    }
}
6.关闭线程

image-20220526224030204

image-20220526224048997

  • 其他方法

    image-20220526224242567

@Slf4j(topic = "c.test7")
public class Test7 {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        Future<String> future1 = executorService.submit(() -> {
            log.debug("start ....1");
            Sleeper.sleep(1);
            log.debug("ok 1");
            return "1";
        });
        Future<String> future2 = executorService.submit(() -> {
            log.debug("start ....2");
            Sleeper.sleep(1);
            log.debug("ok 2");
            return "2";
        });
        Future<String> future3 = executorService.submit(() -> {
            log.debug("start ....3");
            Sleeper.sleep(1);
            log.debug("ok 3");
            return "3";
        });
        log.debug("shutdown");
        executorService.shutdown();
        executorService.awaitTermination(3, TimeUnit.SECONDS);
        log.debug("await...");
    }
}
7.饥饿

image-20220526230601210

@Slf4j(topic = "c.test8")
public class Test8 {
    private static final List<String> MENU = Arrays.asList("套餐1", "套餐2", "套餐3", "套餐4", "套餐5");
    static Random random = new Random();

    static String choose() {
        return MENU.get(random.nextInt(MENU.size()));
    }

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        executorService.execute(() -> {
            log.debug("处理点餐");
            Future<String> future = executorService.submit(() -> {
                log.debug("做菜");
                return choose();
            });

            try {
                log.debug("上菜:{}",future.get());
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        });

        executorService.execute(() -> {
            log.debug("处理点餐");
            Future<String> future = executorService.submit(() -> {
                log.debug("做菜");
                return choose();
            });

            try {
                log.debug("上菜:{}",future.get());
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        });

    }
}

image-20220526231557968

  • 解决

      // 点餐线程只处理点餐 做菜线程只处理做菜
      ExecutorService executorService = Executors.newFixedThreadPool(1);
      ExecutorService cookieService = Executors.newFixedThreadPool(1);
    

image-20220526232251028

8.创建合适的线程池参数

image-20220526232510366

image-20220526233037202

9.任务调度线程池

image-20220526233728402

  • Timer

    @Slf4j(topic = "c.test9")
    public class Test9 {
        public static void main(String[] args) {
            Timer timer = new Timer();
    
            TimerTask t1 = new TimerTask() {
                @Override
                public void run() {
                    log.debug("task 1");
                    Sleeper.sleep(2);
                }
            };
    
            TimerTask t2 = new TimerTask() {
                @Override
                public void run() {
                    log.debug("task 2");
                    Sleeper.sleep(1);
                }
            };
    
            log.debug("start..");
            // timer添加2个任务,delay延迟多久执行
            timer.schedule(t1,1);
            timer.schedule(t2,1);
        }
    }
    
  • ScheduledExecutorService

    @Slf4j(topic = "c.test10")
    public class Test10 {
        public static void main(String[] args) {
            ScheduledExecutorService pool = Executors.newScheduledThreadPool(2);
    
            pool.schedule(() -> {
                log.debug("task 1");
            }, 1, TimeUnit.SECONDS);
    
            pool.schedule(() -> {
                log.debug("task 2");
            }, 1, TimeUnit.SECONDS);
        }
    }
    
    // 定时任务
    @Slf4j(topic = "c.test10")
    public class Test10 {
        public static void main(String[] args) {
            ScheduledExecutorService pool = Executors.newScheduledThreadPool(1);
    
            pool.scheduleAtFixedRate(() -> {
                log.debug("start...");
            }, 1, 1, TimeUnit.SECONDS);
        }
    }
    
    
@Slf4j(topic = "c.test11")
public class Test11 {
    public static void main(String[] args) {
        // 每周五晚上11点执行
        ScheduledExecutorService pool = Executors.newScheduledThreadPool(1);

        LocalDateTime now = LocalDateTime.now();
        // 将当前时间设置为星期五11点
        LocalDateTime dateTime = now.withHour(22).withMinute(30).withSecond(0).withNano(0).with(DayOfWeek.FRIDAY);

        // 如果当前时间大于星期五,那么设置到下一周
        if (now.compareTo(dateTime) > 0) {
            dateTime = dateTime.plusWeeks(1);
        }
        // 延迟多久执行
        long toMillis = Duration.between(now, dateTime).toMillis();
        // 隔多久执行一次
        long loopTime = 1000 * 60 * 60 * 24 * 7;
        pool.scheduleAtFixedRate(() -> {
            log.debug("{}", "每周五晚上11点定时执行");
        }, toMillis, loopTime, TimeUnit.MILLISECONDS);
    }
}

10.线程池处理异常
      ExecutorService executorService = Executors.newFixedThreadPool(1);
        executorService.submit(() -> {
            try {
                log.debug("start...");
                int i = 1 / 0;
            } catch (Exception e) {
                log.error("error...",e);
            }
        });
        Future<Boolean> future = executorService.submit(() -> {
            log.debug("start...");
            int i = 1 / 0;
            return true;
        });
        log.debug("result:{}",future.get());
11.tomcat线程池

image-20220527223415125

image-20220527223615661

image-20220527223848787

image-20220527223918843

  • tomcat线程池配置

    image-20220527224756141

image-20220527224957592

12.Fork/Join

image-20220527225204019

@Slf4j(topic = "c.test12")
public class Test12 {
    public static void main(String[] args) {
        ForkJoinPool pool = new ForkJoinPool(4);
        System.out.println(pool.invoke(new MyJoin(5)));
    }
}

@Slf4j(topic = "c.myJoin")
class MyJoin extends RecursiveTask<Integer> {
    private int i;

    public MyJoin(int i) {
        this.i = i;
    }

    @Override
    public String toString() {
        return "MyJoin{" +
                "i=" + i +
                '}';
    }

    @Override
    protected Integer compute() {
        if (i == 1) {
            log.debug("join(){}", i);
            return i;
        }
        MyJoin join = new MyJoin(i - 1);
        join.fork();
        log.debug("fork(){}+{}", i, join);

        int result = i + join.join();
        log.debug("join(){}+{}={}", i, join, result);
        return result;
    }
}

image-20220527231838607

@Slf4j(topic = "c.test12")
public class Test12 {
    public static void main(String[] args) {
        ForkJoinPool pool = new ForkJoinPool(2);
        System.out.println(pool.invoke(new MyJoin(1,5)));
    }
}

@Slf4j(topic = "c.myJoin")
class MyJoin extends RecursiveTask<Integer> {
    private int begin;
    private int end;

    public MyJoin(int begin, int end) {
        this.begin = begin;
        this.end = end;
    }

    @Override
    public String toString() {
        return "MyJoin{" +
                "begin=" + begin +
                ", end=" + end +
                '}';
    }

    @Override
    protected Integer compute() {
        if (begin == end) {
            log.debug("join(){}", begin);
            return begin;
        }
        if (end - begin == 1) {
            log.debug("join(){}+{}={}", begin, end, end + begin);
            return end + begin;
        }
        int mid = (end + begin) / 2;
        MyJoin myJoin = new MyJoin(begin, mid);// 1 3
        myJoin.fork();
        MyJoin myJoin1 = new MyJoin(mid + 1, end); // 4 5
        myJoin1.fork();
        log.debug("fork(){}+{}=?", myJoin, myJoin1);

        int result = myJoin.join() + myJoin1.join();
        log.debug("join(){}+{}={}", myJoin, myJoin1, result);
        return result;

    }
}

image-20220527233058113

5.JUC

1.aqs

image-20220528092015057

image-20220528092156495

@Slf4j(topic = "c.test13")
public class Test13 {
    public static void main(String[] args) {
        MyLock lock = new MyLock();
        new Thread(() -> {
            lock.lock();
            log.debug("getlock");
            lock.lock();
            log.debug("getlock2...");
            try {
                log.debug("locking");
                Sleeper.sleep(1);
            } finally {
                log.debug("unlocking");
                lock.unlock();
            }
        },"t1").start();

    }
}

// 自定义不可重复锁
class MyLock implements Lock {
    MySync mySync = new MySync();

    class MySync extends AbstractQueuedSynchronizer {
        public MySync() {
        }

        // 枷锁
        @Override
        protected boolean tryAcquire(int arg) {
            if (compareAndSetState(0, 1)) {
                // 设置onwer为当前线程
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        // 释放锁
        @Override
        protected boolean tryRelease(int arg) {
            setExclusiveOwnerThread(null);
            // 保证指令有序性
            setState(0);
            return true;
        }

        // 是否持有独占锁
        @Override
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }

        public Condition getCondition() {
            return new ConditionObject();
        }
    }


    @Override
    public void lock() {
        mySync.acquire(1);
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
        mySync.acquireInterruptibly(1);
    }

    @Override
    public boolean tryLock() {
        return mySync.tryRelease(1);
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return mySync.tryAcquireNanos(1, unit.toNanos(time));
    }

    @Override
    public void unlock() {
        mySync.release(1);
    }

    @Override
    public Condition newCondition() {
        return mySync.getCondition();
    }
}
2.ReentrantLock原理

image-20220528095553877

image-20220528095955873

image-20220528100129140

image-20220528100237878

image-20220528100657773

image-20220528100732433

image-20220528100812011

image-20220528101525696

image-20220528222322940

2.1 可重入原理

image-20220528102235419

image-20220528102313591

2.2可打断原理

image-20220528103436694

image-20220528103459845

image-20220528103624353

image-20220528103755618

image-20220528103845149

2.3公平锁原理
  • 非公平锁实现

image-20220528104039984

  • 公平锁实现

    image-20220528104211971

image-20220528104413792

2.4条件变量原理

image-20220528104849821

image-20220528105224379

image-20220528105112131

image-20220528105423977

  • signal流程

image-20220528105625980

image-20220528105813603

image-20220528222526199

2.5Reentrantlock读写锁
@Slf4j(topic = "c.test14")
public class Test14 {
    public static void main(String[] args) {
        Lock lock = new Lock();
        new Thread(() -> {
            lock.write();
        }, "t1").start();

        new Thread(() -> {
            lock.write();
        }, "t2").start();
    }
}

@Slf4j(topic = "c.lock")
class Lock {
    private Object o;
    private ReentrantReadWriteLock rw = new ReentrantReadWriteLock();
    private ReentrantReadWriteLock.ReadLock r = rw.readLock();
    private ReentrantReadWriteLock.WriteLock w = }

    public void write() {
        log.debug("获取写锁...");
        w.lock();
        try {
            log.debug("写入数据..");
            Sleeper.sleep(1);
        } finally {
            log.debug("释放写锁");
            w.unlock();
        }
    }
}

image-20220528112640038image-20220528113000105

image-20220528113042209

  • 读写锁原理

    image-20220528132750393

image-20220528133447387

image-20220528133629948

image-20220528133837089

image-20220528133935949

image-20220528134732318

image-20220528135327569

image-20220528135732234

image-20220528135759325

  • 读锁的unlock方法image-20220528135924158

image-20220528140220236

image-20220528140350584

image-20220528140447976

3.StampedLock

image-20220528144015717

@Slf4j(topic = "c.test11")
public class StampedLockTest {
    public static void main(String[] args) {
        DataContainer container = new DataContainer(1);
        new Thread(() -> {
            container.read(1);
        }, "t1").start();

        new Thread(() -> {
            container.read(1);
        }, "t2").start();
    }
}

@Slf4j(topic = "c.data")
class DataContainer {

    private int data;
    private final StampedLock lock = new StampedLock();

    public DataContainer(int data) {
        this.data = data;
    }

    public int read(int readTime) {
        long stamp = lock.tryOptimisticRead();
        log.debug("OptimisticReadTime:{}", stamp);
        Sleeper.sleep(readTime);
        if (lock.validate(stamp)) {
            log.debug("read finish..:{}", stamp);
            return data;
        }
        log.debug("updating stamp....{}", stamp);
        try {
            // 验戳失败 重新获取读锁
            stamp = lock.readLock();
            log.debug("read lock..{}", stamp);
            Sleeper.sleep(readTime);
            log.debug("read finish,,,{}", stamp);
            return data;
        } finally {
            log.debug("read unlock..{}", stamp);
            lock.unlockRead(stamp);
        }
    }

    public void write(int newData) {
        long stamp = lock.writeLock();
        log.debug("write lock{}", stamp);
        try {
            Sleeper.sleep(2);
            this.data = newData;
        } finally {
            log.debug("write unlock...{}", stamp);
            lock.unlockWrite(stamp);
        }
    }
}
  • 读读

image-20220528150558538

  • 读写

image-20220528150909719

  • 缺点

    不可重入、不支持条件变量

4.Semphore
  • 信号量 用来限制能够同时访问资源的线程上限

    @Slf4j(topic = "c.test15")
    public class Test15 {
        public static void main(String[] args) {
            Semaphore semaphore = new Semaphore(3);
            for (int i = 0; i < 10; i++) {
                new Thread(() -> {
                    try {
                        semaphore.acquire();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    try {
                        log.debug("runing....");
                        Sleeper.sleep(1);
                        log.debug("end....");
                    } finally {
                        semaphore.release();
                    }
                }, "thread" + i).start();
            }
        }
    }
    
    
  • 加锁流程

    image-20220528154812598

image-20220528154844575

image-20220528154905204

  • 释放锁

image-20220528155320547

5.CountDownLacth

image-20220528155935478

@Slf4j(topic = "c.test16")
public class Test16 {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(3);

        log.debug("wait...");

        new Thread(() -> {
            log.debug("t1.start");
            Sleeper.sleep(1);
            log.debug("t1.finish");
            latch.countDown();
        }, "t1").start();

        new Thread(() -> {
            log.debug("t2.start");
            Sleeper.sleep(2);
            log.debug("t2.finish");
            latch.countDown();
        }, "t2").start();

        new Thread(() -> {
            log.debug("t3.start");
            Sleeper.sleep(3);
            log.debug("t3.finish");
            latch.countDown();
        }, "t3").start();

        latch.await();
        log.debug("gg~~");
    }
}
  • 小案例 lol排位10人等待游戏开始

    @Slf4j(topic = "c.test17")
    public class Test17 {
        public static void main(String[] args) throws InterruptedException {
            ExecutorService pool = Executors.newFixedThreadPool(10);
            String[] arr = new String[10];
            Random random = new Random();
            CountDownLatch latch = new CountDownLatch(10);
            for (int k = 0; k < 10; k++) {
                int j = k;
                pool.submit(() -> {
    
                    for (int i = 0; i <= 100; i++) {
                        try {
                            Thread.sleep(random.nextInt(100));
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        arr[j] = i + "%";
                        System.out.print("\r" + Arrays.toString(arr));
                    }
                    latch.countDown();
                });
            }
            latch.await();
            System.out.print("\n" +" 游戏开始");
        }
    }
    
6.CyclicBarrier

image-20220528173252023

@Slf4j(topic = "c.test18")
public class Test18 {
    public static void main(String[] args) {

        ExecutorService pool = Executors.newFixedThreadPool(2);
        CyclicBarrier barrier = new CyclicBarrier(2, () -> {
            log.debug("start...");
        });
        for (int i = 0; i < 3; i++) {
            pool.submit(() -> {
                log.debug("cyclic start...");
                Sleeper.sleep(1);
                try {
                    barrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            });

            pool.submit(() -> {
                log.debug("cyclic start...");
                Sleeper.sleep(2);
                try {
                    barrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            });
        }
        pool.shutdown();
    }
}
  • 与countdownlacth相比 它的计数器会重置。而count用完就没了

6.线程安全类集合

image-20220528174347338

image-20220528174450767

6.1 jdk7 hashmap死链
6.2 concurentHashMap

image-20220528200442187

image-20220528200527064

image-20220528201440838

image-20220528202038283

image-20220528202618357

image-20220528202821198

image-20220528203213257

image-20220528203351179

image-20220528203506307

image-20220528203830833

image-20220528204118234

image-20220528205755370

  • 扩容流程

    image-20220528210118311

jdk1.7

image-20220528210411083

image-20220528210654694

image-20220528210612022

image-20220528211007335

image-20220528211117878

image-20220528211251080

image-20220528211415988

image-20220528211522745

image-20220528212709276

image-20220528212737984

image-20220528213052100

image-20220528213340665

6.3 LinkedBlockingQueue原理

image-20220528213802961

image-20220528214022923

image-20220528214134693

image-20220528214448845

image-20220528214501643

image-20220528214843808

image-20220528215209769

image-20220528215321296

image-20220528215527523

6.4ConcurrentLinkedQueue

image-20220528215557664

6.5CopyOnWriteArrayList

image-20220528220344234

image-20220528220615174

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值