多线程学习笔记

73 阅读5分钟

多线程学习笔记

一、实现多线程的三种方法

image-20241029104125547

1.继承Thread类

image-20241029104227845

start()开启线程,run()方法顺序执行

image-20241029104611575

image-20241029105549071

一个mian方法下三个thread.start(),不一定顺序执行,cpu安排调度

image-20241029105702173

2.实现runable接口

image-20241029110043201

启动方式不同

image-20241029110308249

多个线程操作一个对象,会造成数据混乱,多个人抢到一张票

image-20241029110757720

如何避免数据混乱得看线程通信

5、synchronized和lock

image-20250205163145055

代码image-20250205164116584

image-20250205164138444

image-20250205164051135

10、ArrayBlockingQueue

四组API

image-20250207142747778

抛出异常

/**
 * add remove element(检测对首元素) 如果超过队列边界(capacity || 0)会抛出异常
 * @author luweitong
 * @date 2025/2/7 16:53
 */
public class Test1 {

    public static void main(String[] args) {
        BlockingQueue<String> strings = new ArrayBlockingQueue<>(3);
        System.out.println(strings.add("a"));
        System.out.println(strings.add("b"));
        System.out.println(strings.add("c"));

        System.out.println(strings.element());

        System.out.println(strings.remove());
        System.out.println(strings.remove());
        System.out.println(strings.remove());
    }
}

不抛出异常

/**
 * offer poll peek(取队列队首元素)有返回值,不会抛出异常
 * @author luweitong
 * @date 2025/2/7 17:00
 */
public class Test2 {
    public static void main(String[] args) {
        BlockingQueue<String> strings = new ArrayBlockingQueue<String>(3);
        System.out.println(strings.offer("a"));
        System.out.println(strings.offer("b"));
        System.out.println(strings.offer("c"));
        System.out.println(strings.offer("d"));

        System.out.println(strings.peek());

        System.out.println(strings.poll());
        System.out.println(strings.poll());
        System.out.println(strings.poll());
        System.out.println(strings.poll());
    }
}

public class Test3 {

    public static void main(String[] args) throws InterruptedException {
        ArrayBlockingQueue<String> strings = new ArrayBlockingQueue<>(3);

        strings.put("a");
        strings.put("a");
        strings.put("a");
        //超出容量就阻塞住了 一直等待
//        strings.put("a");
        System.out.println(strings.take());
        System.out.println(strings.take());
        System.out.println(strings.take());
        //没有元素取,就一直等待
//        System.out.println(strings.take());
    }
}
synchronousQueue同步队列
/**
 * synchronousQueue同步队列
 * 和其他的blockQueue不一样,同步队列不存储元素(只存储一个元素)
 * put了一个元素必须取出来
 * @author luweitong
 * @date 2025/2/7 17:11
 */
public class Test4 {

    public static void main(String[] args) {
        SynchronousQueue<String> queue = new SynchronousQueue<>();
        new Thread(() -> {
            try {
                queue.put("a");
                queue.put("b");
                queue.put("c");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }).start();

        new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName() +"->"+ queue.take());
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName() +"->"+ queue.take());
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName() +"->"+ queue.take());
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }).start();
    }
}

11、线程池(重点)

image-20250207143639051

线程池三大方法

/**
 * @author luweitong
 * @date 2025/2/7 17:22
 */
public class Test1 {
    public static void main(String[] args) {
//        ExecutorService executorService = Executors.newSingleThreadExecutor();//单个线程
//        ExecutorService executorService = Executors.newFixedThreadPool(3);//固定线程
        ExecutorService executorService = Executors.newCachedThreadPool();//可伸缩的

        try {
            for (int i = 0; i < 10; i++) {
                executorService.execute(() -> System.out.println(Thread.currentThread().getName() + "ok"));
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            //使用线程池必须shutdown 不然会OOM
            executorService.shutdown();
        }

    }
}

阿里巴巴规范不让使用Executor直接创建,会有OOM风险因为newFixed和newCached

image-20250207144658639

image-20250207145315199

/**
 * 自定义线程池,模拟银行业务排队
 * @author luweitong
 * @date 2025/2/7 17:32
 */
public class Test2 {
    public static void main(String[] args) {
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
                2,//核心线程数
                5,//最大线程数
                1,//存活时间
                TimeUnit.SECONDS,//存活时间单位
                new ArrayBlockingQueue<Runnable>(3),//阻塞队列
                Executors.defaultThreadFactory(),//线程工厂
//                new ThreadPoolExecutor.AbortPolicy()//拒绝策略 AbortPolicy默认策略超出线程数再使用就不处理,并抛出异常
//                new ThreadPoolExecutor.CallerRunsPolicy()// CallerRunsPolicy 从哪儿来的回哪儿去 输出结果main线程执行了
//                new ThreadPoolExecutor.DiscardPolicy()// DiscardPolicy 直接丢弃任务,不会报错
                new ThreadPoolExecutor.DiscardOldestPolicy()// DiscardOldestPolicy 会和最早的竞争,不会抛出异常
        );

        try {
            for (int i = 0; i < 10; i++) {
                threadPool.execute(() -> {
                    System.out.println(Thread.currentThread().getName() + "执行了");
                });
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            threadPool.shutdown();
        }
    }
}

最大承载 = maximumPoolSize + blockingQueueSize

拒绝策略

image-20250207150654077

应用场景?

image-20250207151216019

12、四大函数式接口

image-20250207151813552

只要是函数式接口都可以用lamda表达式简化

函数式

image-20250207152127786

断言式

image-20250207152515651

消费型接口

image-20250207152947946

供给型接口

image-20250207153043221

13、Stream流式计算

image-20250207153902123

14、forkJoin

image-20250208105021419

image-20250208104946397

工作窃取

image-20250208105236170

forkJoin

image-20250208110113801

image-20250208110416006

image-20250208110641107

image-20250208110741994

image-20250208111025954