【JavaSE】线程通信,线程池,定时器

1. 线程通信

1.1 线程通信概述

在这里插入图片描述

1.2 线程案例模拟

在这里插入图片描述
在这里插入图片描述

1.3 线程通信总结

在这里插入图片描述

2. 线程池(重点)

2.1 线程池概述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

2.2 线程池实现的API,参数说明

在这里插入图片描述

2.2.1 参数说明
  1. 指定线程池的最大的核心线程数,创建线程池需要设定
  2. 线程池支持的最大线程数:核心线程+临时线程
  3. 指定临时线程的最大存活时间
  4. 指定临时线程存活时间的单位
  5. 指定任务队列:当核心线程都处于繁忙状态时,指定任务队列的大小,当请求的任务超过任务队列最大的大小时,才会创建临时线程
  6. 指定使用哪个线程工厂进行创建线程
  7. 指定核心线程和临时线程都忙,任务队列满时,新任务来了的解决方案
    在这里插入图片描述
2.2.2 线程池常见面试题

在这里插入图片描述

2.2.3 总结

在这里插入图片描述

2.3 线程池处理Runnable任务

2.3.1 创建线程池示例

在这里插入图片描述

在创建线程池的最后一个参数我们介绍了当所有线程忙,任务队列满的时候,新任务来了怎么办

这里列举了四种拒绝策略
在这里插入图片描述

2.3.2 代码演示
  • 创建一个Runnable任务对象
public class MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + "输出了:HelloWorld ==> "  + i);
        }
        try {
            System.out.println(Thread.currentThread().getName() + "本任务与线程绑定了,线程进入休眠了~~~");
            Thread.sleep(10000000);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  • 创建一个线程池, 调用线程池的execute方法执行任务
public class ThreadPoolDemo1 {
    public static void main(String[] args) {
        // 1、创建线程池对象
        /**
         public ThreadPoolExecutor(int corePoolSize,
                                 int maximumPoolSize,
                                 long keepAliveTime,
                                 TimeUnit unit,
                                 BlockingQueue<Runnable> workQueue,
                                 ThreadFactory threadFactory,
                                 RejectedExecutionHandler handler)
         */
        ExecutorService pool = new ThreadPoolExecutor(3, 5 ,
                6, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5) , Executors.defaultThreadFactory(),
               new ThreadPoolExecutor.AbortPolicy() );

        // 2、给任务线程池处理。
        Runnable target = new MyRunnable();
        pool.execute(target);
        pool.execute(target);
        pool.execute(target);

        pool.execute(target);
        pool.execute(target);
        pool.execute(target);
        pool.execute(target);
        pool.execute(target);

        // 创建临时线程
        pool.execute(target);
        pool.execute(target);
//        // 不创建,拒绝策略被触发!!!
//        pool.execute(target);

        // 关闭线程池(开发中一般不会使用)。
        // pool.shutdownNow(); // 立即关闭,即使任务没有完成,会丢失任务的!
        pool.shutdown(); // 会等待全部任务执行完毕之后再关闭(建议使用的)
    }
}

创建3个任务的运行结果
在这里插入图片描述
创建8个任务的运行结果
在这里插入图片描述
创建十个线程任务的结果
在这里插入图片描述
创建十一个线程的结果
在这里插入图片描述

总结一下:

我们创建的线程池核心线程为3,最大线程为5,也就是临时线程数为2,任务队列为5,因此,当我们创建3个任务时,核心线程帮我们执行。

当我们创建8个任务时,消息队列刚好满,这时候会等待核心线程处理完毕任务再从消息队列中获取任务。

当我们创建十个任务时,总任务数超过核心线程和消息队列的总和,这时候会创建临时线程来执行任务。

当创建十一个任务时,总任务数超过核心线程+临时线程+消息队列可容纳的数量,因此会触发任务拒绝策略。

2.3.3 总结

在这里插入图片描述

2.4 线程池处理Callable任务

2.4.1 执行Callable任务方法

在这里插入图片描述

2.4.2 代码演示
  • 创建Callable任务
public class MyCallable implements Callable<String>{
    private int n;
    public MyCallable(int n) {
        this.n = n;
    }

    /**
       2、重写call方法(任务方法)
     */
    @Override
    public String call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= n ; i++) {
            sum += i;
        }
        return Thread.currentThread().getName()
                + "执行 1-" + n+ "的和,结果是:" + sum;
    }
}

  • 创建线程池执行Callable任务
public class ThreadPoolDemo2 {
    public static void main(String[] args) throws Exception {
        // 1、创建线程池对象
        /**
         public ThreadPoolExecutor(int corePoolSize,
                                 int maximumPoolSize,
                                 long keepAliveTime,
                                 TimeUnit unit,
                                 BlockingQueue<Runnable> workQueue,
                                 ThreadFactory threadFactory,
                                 RejectedExecutionHandler handler)
         */
        ExecutorService pool = new ThreadPoolExecutor(3, 5 ,
                6, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5) , Executors.defaultThreadFactory(),
               new ThreadPoolExecutor.AbortPolicy() );

        // 2、给任务线程池处理。
        Future<String> f1 = pool.submit(new MyCallable(100));
        Future<String> f2 = pool.submit(new MyCallable(200));
        Future<String> f3 = pool.submit(new MyCallable(300));
        Future<String> f4 = pool.submit(new MyCallable(400));
        Future<String> f5 = pool.submit(new MyCallable(500));

//        String rs = f1.get();
//        System.out.println(rs);

        System.out.println(f1.get());
        System.out.println(f2.get());
        System.out.println(f3.get());
        System.out.println(f4.get());
        System.out.println(f5.get());
    }
}

执行结果:这里调用get方法是因为get方法返回的是线程执行完毕后的结果
在这里插入图片描述

2.4.3 总结

在这里插入图片描述

2.5 Executors工具类实现线程池

2.5.1 常用方法

在这里插入图片描述

2.5.2 Executors工具类使用可能存在的陷阱(注意)

在这里插入图片描述
OOM(Out Of Memory) 内存溢出
在这里插入图片描述

2.5.3 代码演示
public class ThreadPoolDemo3 {
    public static void main(String[] args) throws Exception {
        // 1、创建固定线程数据的线程池
        ExecutorService pool = Executors.newFixedThreadPool(3);

        pool.execute(new MyRunnable());
        pool.execute(new MyRunnable());
        pool.execute(new MyRunnable());
        pool.execute(new MyRunnable()); // 已经没有多余线程了
    }
}

在这里插入图片描述

2.5.4 总结

在这里插入图片描述

3. 定时器

3.1 定时器介绍

在这里插入图片描述

3.2 Timer定时器

在这里插入图片描述

public class TimerDemo1 {
    public static void main(String[] args) {
        // 1、创建Timer定时器
        Timer timer = new Timer();  // 定时器本身就是一个单线程。
        // 2、调用方法,处理定时任务
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行AAA~~~" + new Date());
            }
        }, 0, 2000);

        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行BB~~~"+ new Date());
                //System.out.println(10/0);
            }
        }, 0, 2000);

        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行CCC~~~"+ new Date());
            }
        }, 0, 3000);
    }
}

在这里插入图片描述

我们将第二个任务的 System.out.println(10/0); 打开,观察执行效果
在这里插入图片描述
可以看到,程序遇到异常就直接结束了。这就是使用Timer定时器的弊端

3.3 ScheduledExecutorService定时器

在这里插入图片描述

public class TimerDemo2 {
    public static void main(String[] args) {
        // 1、创建ScheduledExecutorService线程池,做定时器
        ScheduledExecutorService pool = Executors.newScheduledThreadPool(3);

        // 2、开启定时任务
        pool.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行输出:AAA  ==》 " + new Date());
                try {
                    Thread.sleep(100000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, 0, 2, TimeUnit.SECONDS);


        pool.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行输出:BBB  ==》 " + new Date());
                System.out.println(10 / 0);
            }
        }, 0, 2, TimeUnit.SECONDS);


        pool.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行输出:CCC  ==》 " + new Date());
            }
        }, 0, 2, TimeUnit.SECONDS);

    }
}

我们直接带着异常条件进行测试
在这里插入图片描述
分析一下:线程执行完A任务后睡眠了,而线程执行完B任务后挂掉了,但是线程执行C不会受到影响。

这种方式的定时器解决了Timer定时器因任务异常挂掉而不能继续执行任务的弊端。

4. 并发,并行

4.1 什么是并发

在这里插入图片描述

4.2 什么是并行

在这里插入图片描述

4.3 总结

在这里插入图片描述

5. 线程的生命周期

5.1 线程的状态

在这里插入图片描述
在这里插入图片描述

5.2 线程的转换过程

在这里插入图片描述
在这里插入图片描述

5.3 总结

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值