从零学Java 线程池

Java 线程池

文章目录

  • Java 线程池
    • 1 线程池概念
      • 1.1 现有问题
      • 1.2 线程池
    • 2 线程池原理
    • 3 如何使用线程池
      • 3.1 获取线程池
    • 4 创建线程的第四种方式

1 线程池概念

1.1 现有问题

  • 线程是宝贵的内存资源、单个线程约占1MB空间,过多分配易造成内存溢出。
  • 频繁的创建及销毁线程会增加虚拟机回收频率、资源开销,造成程序性能下降。

1.2 线程池

  • 线程容器,可设定线程分配的数量上限。
  • 将预先创建的线程对象存入池中,并重用线程池中的线程对象。
  • 避免频繁的创建和销毁。

2 线程池原理

在这里插入图片描述

将任务提交给线程池,由线程池分配线程、运行任务,并在当前任务结束后复用线程。

3 如何使用线程池

3.1 获取线程池

常用的线程池接口和类(所在包java.util.concurrent):

  • Executor:线程池的顶级接口。
    • execute(); 执行任务
  • ExecutorService:线程池接口,可通过submit(Runnable task) 提交任务代码。
    • shutdown() 关闭线程池
    • isTerminated() 判断线程池中任务和线程是否已经执行完毕。
    • submit() 提交任务
  • Executors工厂类:通过此类可以获得一个线程池。
    • newFixedThreadPool(int nThreads) 获取固定数量的线程池。
      参数:指定线程池中线程的数量。
    • newCachedThreadPool() 获得动态数量的线程池,如不够则创建新的,无上限。

eg:

//1 创建固定数量的线程池
ExecutorService es = Executors.newFixedThreadPool(4);
//2 创建动态数量的线程池
ExecutorService es = Executors.newCachedThreadPool();
public class TestExecutors {
    public static void main(String[] args) {
        //1.1 创建固定数量的线程池
        //ExecutorService es = Executors.newFixedThreadPool(4);
        //1.2 创建动态数量的线程池
        ExecutorService es = Executors.newCachedThreadPool();
        //2 添加任务
        Runnable ticket = new Runnable() {
            private int count = 1000;
            @Override
            public void run() {
                while (true) {
                    synchronized (this) {
                        if (count<=0) {
                            break;
                        }
                        System.out.println(
                                Thread.currentThread().getName()+"卖了第"+count+"张票"
                        );
                        count--;
                    }
                }
            }
        };
        for (int i = 0; i < 4; i++) {
            //提交任务
            es.submit(ticket);
        }
        //3 关闭线程池
        es.shutdown();
    }
}

eg:

//3 创建单线程线程池, 只有一个线程的线程池
public class TestSingThread {
    public static void main(String[] args) {
        //3 创建单线程线程池, 只有一个线程的线程池
        ExecutorService es = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 10; i++) {
            es.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"...");
                }
            });
        }
        es.shutdown();
    }
}

eg:

//4 创建调度线程池, 实现周期执行和延迟执行
public class TestScheduleThread {
    public static void main(String[] args) {
        //4 创建调度线程池, 实现周期执行和延迟执行
        //周期执行: 间隔指定时间执行一次, 不能关闭线程
        ScheduledExecutorService es = Executors.newScheduledThreadPool(1);
        es.scheduleAtFixedRate(new Runnable() {
            int num = 0;
            @Override
            public void run() {
                System.out.println(new Date()+"..."+num);
                num++;
                if (num == 10) {
                    es.shutdown();
                }
            }
        },0,1000, TimeUnit.MILLISECONDS);

        //延迟执行: 延迟一定时间执行
        es.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println(new Date());
            }
        },3000, TimeUnit.MILLISECONDS);
        es.shutdown();
    }
}

eg:

//5 工作窃取线程池
public class TestWorkStealingPool {
    public static void main(String[] args) {
        //5 工作窃取线程池
        //5.1 工作窃取线程池中的都属于后台线程
        //5.2 每一个线程都有自己的双端队列, 队头和队尾都可以加入和删除元素
        //5.3 自己线程的队列中任务执行完后, 会去别的线程队列的队尾窃取一个任务执行
        //默认使用CPU内核个数作为线程个数
        ExecutorService es = Executors.newWorkStealingPool();
        for (int i = 0; i < 10; i++) {
            es.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"...");
                }
            });
        }
        es.shutdown();
        //阻止主线程结束
        while (!es.isTerminated()); //判断线程池中的任务和线程是否执行完毕
        System.out.println("执行完毕");
    }
}

4 创建线程的第四种方式

实现 Callable 接口, 重写 call() 方法

  • JDK5加入,与Runnable接口类似,实现之后代表一个线程任务。
  • Callable具有泛型返回值、可以声明异常。

语法:

public interface Callable<V>{
	public V call() throws Exception;
}

Future接口

  • 概念:异步接收ExecutorService.submit()所返回的状态结果,当中包含了call()的返回值。
  • 方法:V get()以阻塞形式等待Future中的异步处理结果(call()的返回值)

eg:

MyCallable:

public class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        int sum = 0;
        System.out.println(Thread.currentThread().getName()+"开始计算...");
        for (int i = 1; i <= 100; i++) {
            sum+=i;
            Thread.sleep(100);
        }
        System.out.println(Thread.currentThread().getName()+"结束计算...");
        return sum;
    }
}

Test:

public class Test {
    public static void main(String[] args) throws Exception{
        //1 创建可调用对象
        MyCallable mc = new MyCallable();
        //2 创建线程池(单线程线程池)
        ExecutorService es = Executors.newSingleThreadExecutor();
        //3 提交任务
        //Future: 表示线程将要执行完毕的结果
        Future<Integer> future = es.submit(mc);
        //4 获取结果(阻塞方法, 直到线程池中的任务执行完毕才返回)
        System.out.println("结果是:"+future.get());
        //5 关闭线程池
        es.shutdown();
    }
}

课堂案例

eg:

需求:使用两个线程,并发计算1~50、51~100的和,再进行汇总统计。
public class Test {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //创建动态线程池
        ExecutorService es = Executors.newCachedThreadPool();
        //添加任务1
        Future<Integer> f1 = es.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int sum = 0;
                for (int i = 1; i <= 50 ; i++) {
                    sum+=i;
                }
                return sum;
            }
        });
        //添加任务2
        Future<Integer> f2 = es.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int sum = 0;
                for (int i = 51; i <= 100 ; i++) {
                    sum+=i;
                }
                return sum;
            }
        });
        //汇总
        System.out.println("结果为:"+(f1.get() + f2.get()));
        //关闭线程池
        es.shutdown();
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/323627.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

新版网易滑块

突然发现脸皮厚根本没用&#xff0c;大冬天的&#xff0c;风吹过来还是会冷。 大哥们多整件衣裳&#xff0c;好冷&#xff01;&#xff01;&#xff01;&#xff01; 网易更新了&#xff0c;这俩 dt跟f值。 dt为 这里返回的&#xff0c;忽略掉他。 data参数中的d值&#xff…

基于深度学习的时间序列算法总结

1.概述 深度学习方法是一种利用神经网络模型进行高级模式识别和自动特征提取的机器学习方法&#xff0c;近年来在时序预测领域取得了很好的成果。常用的深度学习模型包括循环神经网络&#xff08;RNN&#xff09;、长短时记忆网络&#xff08;LSTM&#xff09;、门控循环单元&a…

【C++】演讲比赛流程管理系统

1、演讲比赛程序需求 2、项目创建 参考之前的案例文章&#xff0c;去创建项目 3、创建管理类 4、菜单功能 5、退出功能 6、演讲比赛功能

【LV12 DAY9 ADC实验】

电压在1501mv~1800mv时&#xff0c;LED2、LED3、LED4、LED5点亮 电压在1001mv~1500mv时&#xff0c;LED2、LED3、LED4点亮 电压在501mv~1000mv时&#xff0c;LED2、LED3点亮 电压在0mv~500mv时&#xff0c;LED2闪烁 #include "exynos_4412.h"void delay(unsigned in…

【从0上手cornerstone3D】核心概念解析(下)

前言 渲染Dicom文件的具体流程请查看&#xff1a;如何渲染一个基础的Dicom文件&#xff08;上&#xff09;Github演示&#xff1a;https://github.com/jianyaoo/vue-cornerstone-demo逻辑图在线链接&#xff1a;逻辑图在线链接在线查看显示效果&#xff08;加载需时间&#xf…

产品经理NPDP

产品经理是告诉团队做正确的事情&#xff0c;项目经理是告诉团队正确地做事情 产品经理的核心能力是商业洞察能力、产品规划与设计、团队管理能力。 产品经理国际资格认证(NPDP)

解决防爬虫机制方法(二)

最近为了完成学校的大数据的作业&#xff0c;老师要我们爬一个的网站&#xff0c;里面有还算不错的防爬机制&#xff0c;忙活了几天&#xff0c;总结出一些常见的防爬机制的应对方法&#xff0c;方法均来自个人实战总结&#xff0c;非专业爬虫角度分析 承接上一次讲的方法解决…

短视频账号矩阵剪辑分发系统无人直播技术开发源头

一、全行业独家源头最全面的核心技术 短视频矩阵新玩法是指利用批量自动混剪系统来处理大量短视频&#xff0c;通过智能算法自动进行视频剪辑、场景切换、特效添加等操作&#xff0c;最终生成高质量、精彩纷呈的混剪视频作品的方法和技术。这一方法的出现使得大规模短视频制作…

实验数据查询

数据查询 一、实验目的 掌握使用SQL的SELECT语句进行基本查询的方法。掌握使用SELECT语句进行条件查询的方法。掌握SELECT语句的GROUP BY、ORDER BY以及UNION子句的作用和使用方法。掌握嵌套查询的方法。掌握连接查询的操作方法。 二、实验内容SQL的SELECT语句进行基本查询的…

Java SE入门及基础(14)

二重循环 1. 什么是二重循环 二重循环就是一个循环结构中又包含另外一个循环结构 while ( 外层循环条件 ){ //外层循环操作 while ( 内层循环条件 ){ //内层循环操作 } //外层循环操作 } while ( 外层循环条件 ){ //外层循环操作 for ( 循环变量初始化 ; 内层循环条…

闪存的基础知识1-Vt的编码

系列文章目录 目录 前言 一、SLC的编码 二、使SLC的编码 三、格雷码的介绍 1.定义&#xff1a; 2.举例 总结 前言 本节主要介绍闪存的一些编码规则 一、SLC的编码 对于SLC来说&#xff0c;可以定义编程态为0、擦除态为1。 二、使SLC的编码 对MLC来说&#xff0c;因为有四个状…

SDK游戏盾是什么?,sdk游戏盾有什么作用

在现今的游戏市场&#xff0c;游戏保护成为了每个游戏开发者都不能忽视的重要环节。恶意破解、作弊和盗版等问题严重影响了游戏的安全性和商业价值。而如何保护自己的游戏免受这些威胁&#xff0c;已经成为游戏开发者们面临的重大挑战。好在SDK游戏盾&#xff0c;它如同保护游戏…

JVM 一些重要配置参数

1、内存配置参数 -Xmx<size>&#xff1a;设置Java堆的最大内存。如 -Xmx2g 将堆的最大大小设置为2G&#xff0c;推荐配置为系统可用内存的70-80%-Xms<size>&#xff1a;设置Java堆的初始内存。如 -Xms2g 将堆的初始大小设置为2G&#xff0c;推荐配置与-Xmx的值相同…

【设计模式-05】Facade门面Mediator调停者 | Decorator装饰器 | Chain Of Responsibility责任链

Facade门面Mediator调停者 1、Facade门面图解 2、Mediator调停者 一般是系统内部相互交错&#xff0c;比如消息中间件(MQ)就是这种设计模式&#xff0c;对各个功能或系统之间进行解耦。 Decorator装饰器 1、问题 2、解决方案 Chain Of Responsibility责任链 一、例子场景 业…

循环冗余校验(Cyclic Redundancy Check, CRC)计算

若信息码字为111000110&#xff0c;生成多项式G(x)x^5x^3x1&#xff0c;则计算出的CRC校验码为&#xff08; &#xff09;。 A.01101 B.11001 C.001101 D.011001 循环冗余校验(Cyclic Redundancy Check, CRC)是一种根据网络数据包或电脑文件等数据产生简短固定位数校验码的…

牛客周赛 Round 3 解题报告 | 珂学家 | 贪心思维场

前言 寒之不寒无水也&#xff0c;热之不热无火也。 整体评价 感觉比较简单&#xff0c;更加侧重于思维吧。和前几场的Round系列&#xff0c;风格不太一样。 A. 游游的7的倍数 因为连续7个数&#xff0c;比如有一个数是7的倍数 因此从个位数中着手添加&#xff0c;是最好的选…

软件测试|如何使用Selenium处理隐藏元素

简介 我们在使用selenium进行web自动化测试时&#xff0c;有时候会遇到元素被隐藏&#xff0c;从而无法对元素进行操作&#xff0c;导致我们的用例报错的情况。当我们遇到元素被隐藏的情况时&#xff0c;需要先对隐藏的元素进行处理&#xff0c;才能继续进行我们的操作&#x…

Spirng MVC见解1

1. SpringMVC概述 1.1 MVC介绍 MVC是一种设计模式&#xff0c;将软件按照模型、视图、控制器来划分&#xff1a; M&#xff1a;Model&#xff0c;模型层&#xff0c;指工程中的JavaBean&#xff0c;作用是处理数据 JavaBean分为两类&#xff1a; 一类称为数据承载Bean&#x…

xlua源码分析(五) struct类型优化

xlua源码分析&#xff08;五&#xff09; struct类型优化 上一节我们分析了xlua是如何实现lua层访问C#值类型的&#xff0c;其中我们重点提到了xlua默认实现方式下&#xff0c;struct访问的效率问题。实际上&#xff0c;xlua还提供了两种优化的方式&#xff0c;可以大大提高str…

代码随想录算法训练营Day21| 93.复原IP地址、78.子集、90.子集||

LeetCode 93 复原 IP 地址 本题思路&#xff1a;最重要的是想到一个收集结果的条件&#xff0c;也就是终止条件。 当 . 的个数达到三个时候&#xff0c;并且&#xff0c;判断最后剩余的是否符合要求&#xff0c;如果符合&#xff0c;说明整个ip地址可以&#xff0c;就加入到结…