首页 > 编程语言 >JAVA高级之线程池

JAVA高级之线程池

时间:2024-07-10 19:00:01浏览次数:20  
标签:状态 JAVA 创建 高级 任务 线程 执行 等待

线程的状态(6种)

线程状态具体含义
NEW一个尚未启动的线程的状态。也称之为初始状态、开始状态。线程刚被创建,但是并未启动。还没调用start方法。MyThread t = new MyThread()只有线程象,没有线程特征。
RUNNABLE当我们调用线程对象的start方法,那么此时线程对象进入了RUNNABLE状态。那么此时才是真正的在JVM进程中创建了一个线程,线程一经启动并不是立即得到执行,线程的运行与否要听令与CPU的调度,那么我们把这个中间状态称之为可执行状态(RUNNABLE)也就是说它具备执行的资格,但是并没有真正的执行起来而是在等待CPU的度。
BLOCKED当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状态;当该线程持有锁时,该线程将变成Runnable状态。
WAITING一个正在等待的线程的状态。也称之为等待状态。造成线程等待的原因有两种,分别是调用Object.wait()、join()方法。处于等待状态的线程,正在等待其他线程去执行一个特定的操作。例如:因为wait()而等待的线程正在等待另一个线程去调用notify()或notifyAll();一个因为join()而等待的线程正在等待另一个线程结束。
TIMED_WAITING一个在限定时间内等待的线程的状态。也称之为限时等待状态。造成线程限时等待状态的原因有三种,分别是:Thread.sleep(long),Object.wait(long)、join(long)。
TERMINATED一个完全运行完成的线程的状态。也称之为终止状态、结束状态

什么是线程池

        概念:线程池是一种基于池化思想管理和使用线程的机制,用于避免频繁创建和销毁线程的开销,并控制并发执行的线程数量。说白了就是用来管理线程的池子。

        组成:线程池通常由线程池管理器、工作队列和线程池中的线程组成。管理器负责任务的分配和线程的管理,工作队列存储等待执行的任务,而线程池中的线程则是实际执行任务的单元。

        优点:使用线程池可以提高系统的性能和资源利用率,因为它减少了在创建和销毁线程上的时间开销,同时也帮助控制了并发执行的线程数量,避免了资源过度消耗。

        工作原理:线程池预先创建一定数量的线程并保存在池中。当有任务需要执行时,线程池会从池中取出一个空闲线程来执行该任务。任务完成后,线程不会销毁而是返回线程池中等待执行下一个任务。这种做法避免了每次处理任务时创建和销毁线程的开销,同时也避免了线程数量过多导致的过度调度问题。

为什么使用线程池

  1. 解决频繁创建线程和销毁线程消耗的性能。

  2. 解决大量创建线程而导致的内存泄露问题。

如何创建线程池

设计思路

  1. 准备一个任务容器

  2. 一次性启动多个(2个)消费者线程

  3. 刚开始任务容器是空的,所以线程都在wait

  4. 直到一个外部线程向这个任务容器中扔了一个"任务",就会有一个消费者线程被唤醒

  5. 这个消费者线程取出"任务",并且执行这个任务,执行完毕后,继续等待下一次任务的到来

方案一

通过工具类完成线程池的创建------Executors

语法简单。但是阿里巴巴不建议使用

  1. 固定大小的线程池对象newFixedThreadPool

  2. 单一线程池: newSingleThreadExecutor

  3. 可变线程池: newCachedThreadPool

  4. 延迟线程池: newScheduledThreadPool

代码如下

public class Test01 {
    public static void main(String[] args) {
        //创建一个固定大小的线程池。返回类型为ExecutorService.
//        ExecutorService executorService = Executors.newFixedThreadPool(5);
        //创建单一线程池【池子里面只有一个线程的对象】适合任务顺序执行的。
//        ExecutorService executorService = Executors.newSingleThreadExecutor();
        //创建可变线程池。【池子中线程的数量会随着任务的大小而变化】
//        ExecutorService executorService = Executors.newCachedThreadPool();
        //延迟线程池:[指定时间后执行]
        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);

        //执行线程任务。Runnable  Callable. Integer.MAX()整数的最大值。
//        for(int i=0;i<10;i++) {
            //1.必须传递Runnable对象。[1]自己创建一个类实现Runnable接口  [2]匿名内部类对象 [3]lambda表达式: 前提接口必须为函数式接口。
//            executorService.execute(new My());
//            executorService.execute(new Runnable() {
//                @Override
//                public void run() {
//                    System.out.println(Thread.currentThread().getName()+"*************");
//                }
//            });
            //表示10秒后执行任务代码块。
//            executorService.schedule(()->{
//                System.out.println(Thread.currentThread().getName()+"~~~~~~~~~~~~~~~");
//            },10, TimeUnit.SECONDS);
            executorService.scheduleAtFixedRate(()->{
                System.out.println(Thread.currentThread().getName());
            },5,2,TimeUnit.SECONDS);
//        }

        //关闭线程池



    }
}

延伸问题---execute和submit方法区别?

        这两个方法都是用来执行线程任务,但是execute属于Executor类中的方法,而submit属于ExecutorService接口中的方法。 而且submit可以执行runnable和callable类型的任务,而execute只能执行Runnable类型的任务。 submit执行完任务后有返回结果。

方案二

通过线程池类: ThreadPoolExecutor类.

语法复杂,但是阿里巴巴建议使用。因为其比较灵活。

代码如下:

package com.Hanshy123.demo07;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Test02 {
    public static void main(String[] args) {
        //核心参数的意思
        /**
         * int corePoolSize,核心线程数的个数 2
         *  int maximumPoolSize,最大线程数量 5
         * long keepAliveTime, 非核心线程允许空闲的时间
         * TimeUnit unit, 时间的单位
         * BlockingQueue<Runnable> workQueue 堵塞队列中 3
         */
        BlockingQueue<Runnable> workQueue=new ArrayBlockingQueue(5);
        ThreadPoolExecutor poolExecutor=new ThreadPoolExecutor(2,6,10, TimeUnit.SECONDS,workQueue);

        for (int i = 0; i <11; i++) {
            poolExecutor.submit(()->{
                System.out.println(Thread.currentThread().getName()+"~~~~~~~~~~~~~~~~");
            });
        }
    }
}

线程池---参数详解

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)
    
corePoolSize:   核心线程的最大值,不能小于0
maximumPoolSize:最大线程数,不能小于等于0,maximumPoolSize >= corePoolSize
keepAliveTime:  空闲线程最大存活时间,不能小于0
unit:           时间单位
workQueue:      任务队列,不能为null
threadFactory:  创建线程工厂,不能为null      
handler:        任务的拒绝策略,不能为null  

标签:状态,JAVA,创建,高级,任务,线程,执行,等待
From: https://blog.csdn.net/Hanshy123/article/details/140331615

相关文章

  • Java中类和对象概述
    目录前言:一.初步了解类和对象1.1什么是面向对象?1.2什么是类和对象?​二.类的定义与使用2.1类的格式与定义2.2对象的创建与使用 三.this关键字的使用3.1this的使用方法3.2this引用的特性 四.类的构造方法 五.静态变量和静态方法前言:小编也是第一次写blog,可能......
  • 每天两道Java面试题(一)
    1、this关键字和super关键字的区别及联系this关键字用在本类中。在类的内部,可以在任何方法中使用this引用当前对象。this关键字是用来解决全局变量和局部变量之间的冲突。this()可以调用同类中重载的构造方法,并且需要放在第一行。super关键字用在子类中。在子类中可以通......
  • Redis是单线程还是多线程的?
    讲Redis是单线程还是多线程的需要根据redis各版本的一个变化,在Redis的老版本中,redis是单线程的,redis的数据处理读写命令都是由一个线程完成,并且速度很快,是因为redis的数据都是存储在内存中的,避免了磁盘I/O的瓶颈,有通过非阻塞IO和事件驱动模型,使得单线程依旧可以处理大量的数据......
  • 使用Java9 Flow API进行Reactive Programming
    importjava.util.concurrent.Flow;importjava.util.concurrent.Flow.Publisher;importjava.util.concurrent.Flow.Subscriber;publicclassReactiveExample{publicstaticvoidmain(String[]args){//创建一个发布者,发布一系列的数字Publisher......
  • Java Executors类的9种创建线程池的方法及应用场景分析
    在Java中,Executors类提供了多种静态工厂方法来创建不同类型的线程池。在学习线程池的过程中,一定避不开Executors类,掌握这个类的使用、原理、使用场景,对于实际项目开发时,运用自如,以下是一些常用的方法,来一一细说:newCachedThreadPool():创建一个可缓存的线程池,如果线程池中......
  • 【unix高级编程系列】标准I/O
    背景在上一篇文章unix高级编程系列之文件I/O中,我们已经介绍了文件I/O是非缓存的,那么与非缓存I/O对应的就是具有缓存的I/O。而标准I/O库就是具有缓存的I/O,今天我们就来认识一下它的独特魅力及相关注意事项。标准I/O与文件I/O的区别我个人认为标准I/O和文件I/O存在以下......
  • 你真的懂多线程吗?多线程 并行处理 CPU 操作系统
    了解多线程、并行处理首先需要了解什么CPU、CPU核数、操作系统CPU物理数即电脑拥有的物理CPU数量,普通电脑一般只有一个CPU插槽,也就是只有一个物理CPU。我们日常说的CPU,就是指封装好的一个物理CPU,作为商品进行售卖。但在编程讨论时,某些情况下,我们说的CPU含义又是指其中一个运算......
  • Java面向对象小游戏--文字版格斗游戏(附带全套源代码)->基于JavaBean
    一、前言java部分的基础学习已经完结,接下来给大家分享的大多为java相关的案例分析,也会有一些小项目,这点不要太过于担心,主要还是基础部分要打牢固。java部分的难点就在面向对象这一点,学习C语言的小伙伴们应该是第一次听说方法。这点也是和C语言相差巨大的地方,不过对于学习过pyt......
  • Java面向对象基础篇综合训练(附带全套源代码及逐语句分析)->基于javabeen
    一、前言还是那句话面向对象是Java的重点,同时也是难点,小编会在此部分分享一些综合型的案例,难度从易到难,本篇文章只是一些基础的操作,综合能力并不是太高。大家可以试着观看一遍自己去打开编译器尝试一下。不知道有多少读者是跟着小编进行学习的,今天是学习Java的第五天,希望大家......
  • JavaScript如何将字符串形式里的img图片添加属性
    方法一:使用正则表达式以下例子中将会在img图片中添加crossorigin属性lethtml=`<p>打撒抠脚大汉噶刷卡机很大凯撒</p><p>规范化是的冯绍峰东风浩荡试试</p><imgsrc="http://s3.v.360xkw.com/yzb/photos/1688536327316_ca0e2e3d.jpg"alt=""......