Java十分钟入门多线程下篇

目录
  • 1、线程池:
  • 2、创建线程池:
    • 1、newCacheThreadPool:
    • 2、newSingleThreadExecutor:
    • 3、newFixedThreadPool(inta):
    • 4、newScheduledTreadPool:
  • 3、线程池创建自定义线程:
  • 4、Runnable和Callable的区别:
  • 5、线程池总结:

1、线程池:

什么是线程池?

咱们也不看长篇大论,通俗的来讲,线程池就是装线程的容器,当需要用的时候去池里面取出来,不用的时候放回去或者销毁。这样一个线程就可以反复的利用,通过线程的这种反复利用机制,可以有效地避免直接创建线程所带来的坏处。

线程池有什么好处?

  • 降低了资源的消耗(CPU)
  • 提高任务执行的响应速度
  • 提高线程的可管理性

线程池创建流程图:

其实通过这个图就可以看到线程池的处理过程:

  • 有新任务进来,判断核心线程池是否满了,是:进入排,否:创建任务
  • 在等待队列判断是否排满了,是:进入线程池 ,否:任务加入队列
  • 判断线程池是否满了,是:拒绝执行任务,否:创建线程执行

2、创建线程池:

先看一下官网给出的创建方法(部分):

完整的可以参考官方文档:

https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/concurrent/Executors.html

这里介绍四种常用的创建类型:

  • newCacheThreadPool(创建一个可缓存的线程池,有任务时才会创建新的线程)
  • newSingleThreadExecutor(创建一个单线程池,线程池中只有一个线程)
  • newFixedThreadPool(int a) (创建固定线程数量的线程池,输入参数:int类型)
  • newScheduledTreadPool (创建一个固定长度的线程池,并且以延时或定时的方式来执行线程)

1、newCacheThreadPool:

创建可缓存的线程对象,意思是这个任务需要几个线程来处理,就会创建几个线程:

线程需要执行的类:

public class MyRunnable implements Runnable{

    int num;

    public MyRunnable(int num) {
        this.num = num;
    }

    @Override
    public void run() {

        System.out.println(Thread.currentThread().getName()+"执行了:"+num);
    }
}

测试类:

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

        //创建单个线程池对象,里面线程只有一个
        ExecutorService cachedService = Executors.newCachedThreadPool();

        //执行5个任务
        for (int i = 1; i<= 5; i++) {
            cachedService.execute(new MyRunnable(i));
        }
    }
}

来看看结果:

OK,上述代码线程池用了5个线程来处理,那么如果我们在每次运行前加一次线程休眠会怎么样? 在每次执行后需要休眠0.5秒(500毫秒):

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

        //创建一个缓存的线程池对象

        ExecutorService cachedService = Executors.newCachedThreadPool();

        for (int i = 1; i<= 5; i++) {
                cachedService.execute(new MyRunnable(i));
                //线程休眠:
                try{
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
        }
    }
}

看看结果:

小结:

  • 如果没有加线程休眠,线程池默认会创建多个线程池对象来帮你完成任务,执行更快完成并且销毁内存,释放资源。
  • 如果添加了线程休眠,线程池会认为同少量的线程对象就可以完成这个任务,就不会帮你创建多个线程对象(因为时间足够,就没必要再创建)

2、newSingleThreadExecutor:

这个方法是创建只有一个线程的线程池,不管怎么样,多只有一个线程来帮你执行任务:

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

        //创建单个线程池对象,里面线程只有一个
        ExecutorService singleService = Executors.newSingleThreadExecutor();

        //执行一百万次任务
        for (int i = 1; i<= 1000000; i++) {
            singleService.execute(new MyRunnable(i));
        }
    }
}

看看结果:

对吧,执行了1000000次也是一个线程在执行,因为这个线程池里面只有一个线程呀。

3、newFixedThreadPool(int a):

这个方法就是创建固定线程数的线程池,比如我要一个这个池里面有10个线程,在后面输入参数即可:

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

        //线程池创建固定数量的线程对象来执行任务,这里创建10个线程对象,由线程池管理生命周期
        ExecutorService singleService = Executors.newFixedThreadPool(10);
        //执行10个任务
        for (int i = 1; i<= 100; i++) {
            singleService.execute(new MyRunnable(i));
        }
    }
}

看看结果:

4、newScheduledTreadPool :

创建一个固定长度的线程池,并且以延时或定时的方式来执行线程,也就是说使用这个方法创建的线程池可以自定义每次执行的时间:

Demo:

public class MyRunnable implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"延迟5秒执行,并且每2秒执行一次该任务:");
    }
}

测试类:

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

        //线程池创建一个定时任务的线程对象
        ScheduledExecutorService service = Executors.newScheduledThreadPool(4);
        /**
         *定时器执行的任务,并且按周期执行
         * 参数1:线程任务
         * 参数2:5秒之后开始执行
         * 参数3:执行后每2秒为一个周期去循环执行
         * 参数4:时间单位。枚举类型,我这指定秒(可以参考API)
         */
        service.scheduleAtFixedRate(new MyRunnable(),5,1, TimeUnit.SECONDS);
    }
}

看看结果:

3、线程池创建自定义线程:

当以上四种线程池满不足业务需求的时候,咱们也可以自定义线程池:

先来一个线程执行类:

public class MyRunnable implements Runnable{

    int num;

    public MyRunnable(int i) {

        this.num = num;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"执行了"+num);
    }
}

测试类:

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

        /**
         * 参数1:线程池有5个固定的线程对象
         * 参数2:当线程池的线程忙不过来的时候,最大线程数为7,也就是说线程对象就可以增加到7个(其中2个是临时线程)
         * 参数3:当临时线程对象超出300毫秒的时候还没有接到新任务,线程池就自动 销毁临时的线程对象
         * 参数4:时间单位。这指定秒,具体参考TimeUnit的枚举类型
         * 参数5:等待执行的任务序列4个(其中有4个任务序列等待线程池对象来执行任务)
         */

        ThreadPoolExecutor executor = new ThreadPoolExecutor(5,7,300,
        					TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(4));

        for (int i = 0; i < 6; i++) {
            executor.execute(new MyRunnable(i));
            showInfo(executor);
        }
    }

	//获取线程的一些信息
    private static void showInfo(ThreadPoolExecutor executor) {
        System.out.println("线程池的总数量:"+executor.getPoolSize());
        System.out.println("队列中等待执行的任务数:"+executor.getQueue().size());
        System.out.println("已经执行完毕的任务数:"+executor.getCompletedTaskCount());
        System.out.println("---------");
    }
}

4、Runnable和Callable的区别:

Runnable是不返还值的,而Callable可以返回值,具体可以看这篇博客(其实主要我也没深入学习这个哈哈): Runnable和Callable的区别

5、线程池总结:

通过这个文章,咱们对线程池有了基础的了解,如何去创建和使用,但这仅仅是最简单的,线程是一个复杂的东西,大家也可以参考其他技术博客来深入学习和研究,在创建线程池的时候,根据场景,合理设置线程池的各个参数,包括线程池数量、队列、线程工厂和拒绝策略,让资源更好的利用起来,这也是优化性能的关键。

到此这篇关于Java十分钟入门多线程下篇的文章就介绍到这了,更多相关Java 多线程内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java十分钟入门多线程上篇

    什么是多线程? 在学习前,我们先对程序.进程.线程.并行.并发有个基础的概念了解: 程序: 为完成指定任务,用编程语言编写的一组指令的集合,即指一段静态的代码,静态对象. 进程: 是程序的一次执行过程,是一个动态的过程,进程自身有产生.使用和消亡的过程.(也称为生命周期,在后面会介绍) 线程: 进程可进一步细化为线程,是一个程序内部的一条执行路径,也就是进程内有线程 并行: 指两个或者多个事件在同一时刻发生,(同时发生) 并发: 指两个或者多个事件在同一个时段内发生,(并不是同时发生) 更好的理

  • Java多线程之线程安全问题详解

    目录 1.什么是线程安全和线程不安全? 2.自增运算为什么不是线程安全的? 3.临界区资源和竞态条件 总结: 面试题: 什么是线程安全和线程不安全? 自增运算是不是线程安全的?如何保证多线程下 i++ 结果正确? 1. 什么是线程安全和线程不安全? 什么是线程安全呢?当多个线程并发访问某个Java对象时,无论系统如何调度这些线程,也无论这些线程将如何交替操作,这个对象都能表现出一致的.正确的行为,那么对这个对象的操作是线程安全的. 如果这个对象表现出不一致的.错误的行为,那么对这个对象的操作不是

  • Java十分钟入门多线程中篇

    目录 1.线程的调度: 1.设置优先级(Priority): 2.休眠(sleep) 3.强制运行(join) 4.礼让(yield) 2.定时器线程: 3.线程的同步: 举例说明: 我们知道飞机在天上飞行是有固定的航线(可以理解成线程),每个机场都有最大的运行负载能力,当运行情况超过了负载能力的时候,这就需要塔台调度参与,会根据每架飞机的优先级排序.当在航线的时候,如果出现紧急情况,会让其他飞机避让,让这架飞机优先级提高,先降落.这就是调度,计算机程序线程运行也是这样的. 1.线程的调度: 在

  • 一篇文章带你Java多线程入门

    目录 多线程的四种创建方式 1.继承Thread类 2.实现Runnable接口 3.实现Callable接口 4.使用线程池 线程的优先级 测试Thread中常用的方法 线程的生命周期 多线程的同步控制 1.同步代码块 2.同步方法 3.同步锁 线程通信 wait/notify模式 sleep和wait的异同 总结 多线程的四种创建方式 1.继承Thread类 /* * 多线程的创建,方式一:继承Thread类 * 1.创建一个继承于Thread类的子类 * 2,重写Thread类的run()

  • 高价值Java多线程面试题分析

    问题一 A线程正在执行一个对象中的同步方法,B线程是否可以同时执行同一个对象中的非同步方法? 可以,两个线程运行所需资源不同,不需要抢占. 案例一. package duoxiancheng2; /** * @author yeqv * @program A2 * @Classname Ms1 * @Date 2022/2/7 19:08 * @Email w16638771062@163.com */ public class Ms1 { //A线程正在执行一个对象中的同步方法,B线程是否可以

  • Java十分钟入门多线程下篇

    目录 1.线程池: 2.创建线程池: 1.newCacheThreadPool: 2.newSingleThreadExecutor: 3.newFixedThreadPool(inta): 4.newScheduledTreadPool: 3.线程池创建自定义线程: 4.Runnable和Callable的区别: 5.线程池总结: 1.线程池: 什么是线程池? 咱们也不看长篇大论,通俗的来讲,线程池就是装线程的容器,当需要用的时候去池里面取出来,不用的时候放回去或者销毁.这样一个线程就可以反复

  • Java十分钟精通集合的使用与原理下篇

    List集合: ArrayList: 底层是数组结构,储存有序并且可以重复的对象 package SetTest; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class ArrayListTest { public static void main(String[] args) { //创建ArrayList的对象 List<Integer> list = ne

  • 十分钟上手正则表达式 下篇

    目录 一.正则表达式常用符号 1.1 问号[?] 1.2 加号[+] 1.3 花括号{} 1.4 管道符号[|] 1.5 小括号() 二.正则表达式实战示例 示例1: 示例2: 前面,我们就正则表达式一些常用的基本方法做了详细的介绍,本篇会讲解一些拓展性的知识,主要的就是常见的ERE模式符号以及shell脚本中常见的一些正则表达式例子. 快速学习正则表达式,不用死记硬背,示例让你通透(上篇) 一.正则表达式常用符号 本章示例着重于在gawk程序脚本中的较常见的ERE模式符号. 1.1 问号[?]

  • Java十分钟精通String类的各种使用方法

    String String类: 代表字符串,提供了开发中常用的字符串处理的方法,如:求字符串的长度.截取字符串.替换字符串等方法,符串是常量,它的值创建之后就不可以再修改了. 首先我们先查一下官方文档,看看官方给String类定了什么方法: String也是属于java.lang包,所以不需要导入,这里就部分展示,全部的内容可以参考: https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.htm

  • Java十分钟精通Lambda表达式

    目录 1.简介 2.Lambda表达式的使用: 1.在普通方法内的使用 2.带参方法的使用 3.Lambda表达式实现多线程 4.Lambda表达式操作运算 5.Lambda表达式方法引用 6.Lambda表达式对集合的使用 3.总结 1.简介 首先Lambda表达式是属于Java8的 一个新特性,提供Java编程中对于函数式编程的支持,有助于代码的简洁,可以取代大半部分的匿名函数,尤其对于集合的遍历和集合的操作,极大的简化了代码. Lambda表达式的主体: 函数式接口: 注意: Lambda

  • Java十分钟精通多态与抽象类的使用与原理

    我们知道Java的三大特性:封装.继承.多态.前两个之前在Java入门(六)已经讲到,现在来讲多态这个特性. 什么是多态? 多态顾名思义即为多种形态的意思 Java中多态的含义: 发送消息给某个对象,让这个对象自行决定采用哪种行为响应这个消息 子类对象的引用赋值给父类引用变量来实现动态的方法调用 Java中形成多态的前提: 继承 父类方法的重写 向上转型 我对多态的解释: 比如我们,是人,也是学生,也是年轻人,我可以用人的身份去做事情,也可以用学生的身份去买学生票,也可以用年轻人的身份做公益,这

  • Java十分钟快速掌握单例模式

    目录 前言 1.什么是单例模式: 2.单例模式的优缺点: 3.懒汉模式(比较常用) 4.饿汉模式[推荐使用] 5.单例模式的应用场景 6.单例模式的应用实例 小结: 前言 首先在Java中有23种设计模式: 创建型模式: 工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式结构型模式: 适配器模式.装饰者模式.代理模式.外观模式.桥接模式.组合模式.享元模式行为型模式::策略模式.模板方法模式.观察者模式.迭代子模式.责任链模式.命令模式.备忘录模式.状态模式.访问者模式.中介者模式.解释

  • Spring Security十分钟入门教程

    目录 写在前面 目标 开始 不引入Spring Security访问接口 引入Spring Security访问接口 退出登录 后记 写在前面 我们在学习技术的过程中,学习的渠道大概有以下几种:看书,视频,博客.我们会发现,一种技术开始流行的时候,各种形式的讲述也就出现了.那么,出书,录视频,写博客的人,在他们之前,是没有什么现成的东西让他们学习的,他们是怎么上手的呢?换句话说,怎么才能有效的快速的上手一门技术呢? 这篇文章,我们一起从零开始学习SpringSecurity,技术点不重要,重要的

随机推荐