当前位置: 首页 > news >正文

微服务 第一章 Java线程池技术应用

系列文章目录

第一章 Java线程池技术应用

在这里插入图片描述


文章目录

  • 系列文章目录
    • @[TOC](文章目录)
  • 前言
  • 1、Java创建线程方式回顾
    • 1.1、继承Thread类(只运行一次)
      • 1.1.1、改造成主线程常驻,每秒开启新线程运行
      • 1.1.2、匿名内部类
      • 1.1.3、缺点
      • 1.1.4、扩展知识:Java内部类
        • 1.1.4.1、静态内部类
        • 1.1.4.2、匿名内部类
    • 1.2、实现Runnable接口
      • 1.2.1、普通类实现Runnable接口
      • 1.2.2、匿名方式创建Runnable实现类
      • 1.2.3、使用Lambda方式创建匿名Runnable类
      • 1.2.4、缺点
      • 1.2.5、扩展Lambda表达式
    • 1.3、实现Callable接口
      • 1.3.1、普通类实现Callable接口
  • 2、线程池
    • 2.1、五种创建线程的方式
    • 2.2、new ThreadPoolExecutor()创建线程
      • 2.2.1、拒绝策略

前言

介绍Java的线程、线程池等操作

1、Java创建线程方式回顾

1.1、继承Thread类(只运行一次)

public class ThreadTest extends Thread{@Overridepublic void run() {System.out.println(Thread.currentThread().getName());}public static void main(String[] args) {new ThreadTest().start();}
}

1.1.1、改造成主线程常驻,每秒开启新线程运行


import java.util.Date;@Slf4j
public class ThreadTest extends  Thread{@Overridepublic void run() {log.info("线程名称:{} , 当前时间:{}" , Thread.currentThread().getName() , new Date().getTime() );}public static void main(String[] args) {while (true) {try {new ThreadTest().start();Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}log.info("主线程常驻");}}}

1.1.2、匿名内部类

import lombok.extern.slf4j.Slf4j;@Slf4j
public class ThreadTest extends  Thread{public static void main(String[] args) {Thread thread = new Thread() {@Overridepublic void run() {log.info("Hello {}" , "world");}};thread.start();}}

1.1.3、缺点

继承了Thread类之后,就不能继承其他类

1.1.4、扩展知识:Java内部类

成员内部类(外部类内部使用,外部类外部使用)


import lombok.extern.slf4j.Slf4j;@Slf4j
public class Outer {public static void main(String[] args) {Inner inner = new Outer().initTest();log.info(inner.innerTest());}public Inner initTest(){Inner inner = new Inner();return  inner;}class Inner{public Inner(){}public Inner(String s){}public String innerTest(){return "Inner Hello world";}}
}

1.1.4.1、静态内部类

import lombok.extern.slf4j.Slf4j;@Slf4j
public class Outer {public static void main(String[] args) {Inner inner = new Inner();log.info(inner.innerTest());}public void initTest(){Inner inner = new Inner();}static class Inner{public Inner(){}public Inner(String s){}public String innerTest(){return "Inner Hello world";}}
}

1.1.4.2、匿名内部类

import lombok.extern.slf4j.Slf4j;@Slf4j
public class Outer {public static void main(String[] args) {Outer outer = new Outer();outer.sayHello();}public void sayHello(){IMessage iMessage = new IMessage() {//匿名类@Overridepublic String sayHello() {return "Hello world";}};log.info(iMessage.sayHello());}interface IMessage{String sayHello();}}

1.2、实现Runnable接口

1.2.1、普通类实现Runnable接口

import lombok.extern.slf4j.Slf4j;@Slf4j
public class StatSales implements Runnable{@Overridepublic void run() {log.info("统计销量");}public static void main(String[] args) {Thread thread = new Thread() {@Overridepublic void run() {log.info("Hello world");}};thread.start();}
}

1.2.2、匿名方式创建Runnable实现类

public static void main(String[] args) {Runnable runnable = new Runnable() {@Overridepublic void run() {System.out.println("统计成绩");}};new Thread(runnable).start();}

1.2.3、使用Lambda方式创建匿名Runnable类

// 使用 Lambda 匿名 Runnable 方式
Thread t3 = new Thread(() -> {
//添加业务方法…
});
// 启动线程
t3.start();

public static void main(String[] args) {Thread thread = new Thread(() -> {System.out.println("统计平均寿命");});thread.start();
}

1.2.4、缺点

不能获得程序的执行结果

1.2.5、扩展Lambda表达式

把函数作为一个方法的参数
表达式语法:

(parameters) -> expression

(parameters) ->{ statements; }

说明:

  • 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
  • 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
  • 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
  • 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定表达式返回了一个数值。
  • 举例:

    // 1. 不需要参数,返回值为 5  
    () -> 5  // 2. 接收一个参数(数字类型),返回其2倍的值  
    x -> 2 * x  // 3. 接受2个参数(数字),并返回他们的差值  
    (x, y) -> x – y  // 4. 接收2个int型整数,返回他们的和  
    (int x, int y) -> x + y  // 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)  
    (String s) -> System.out.print(s)
    

    1.3、实现Callable接口

    FutureTask+Callable

    1.3.1、普通类实现Callable接口

    public class StatScore implements Callable<Double> {@Overridepublic Double call() throws Exception {//统计分数的逻辑return 88.98;}
    }
    
     public static void main(String[] args) throws ExecutionException, InterruptedException {StatScore statScore = new StatScore();//跟FutureTask 关联上FutureTask<Double> doubleFutureTask = new FutureTask<>(statScore);//跟Thread关联上Thread thread = new Thread(doubleFutureTask);thread.start();log.info(String.valueOf(doubleFutureTask.get()));}
    

    2、线程池

    线程池就是存放线程的池子,池子里存放了很多可以复用的线程。
    使用线程池的优势

  • 提高效率,创建好一定数量的线程放在池中,等需要使用的时候就从池中拿一个,这要比需要的时候创建一个线程对象要快的多。
  • 减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
  • 提升系统响应速度,假如创建线程用的时间为T1,执行任务用的时间为T2,销毁线程用的时间为T3,那么使用线程池就免去了T1和T3的时间;
  • 在这里插入图片描述

    2.1、五种创建线程的方式

    //创建一个单线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行
    ExecutorService executorService = Executors.newSingleThreadExecutor();
    //创建一个定长的线程池,可控制最大并发数,超出的线程进行队列等待。 ExecutorService executorService =
    Executors.newFixedThreadPool(2); //可以创建定长的、支持定时任务,周期任务执行。
    ExecutorService executorService = Executors.newScheduledThreadPool(2);
    //创建一个可以缓存的线程池,如果线程池长度超过处理需要,可以灵活回收空闲线程,没回收的话就新建线程 ExecutorService
    executorService = Executors.newCachedThreadPool(); //创建一个具有抢占式操作的线程池
    ExecutorService executorService = Executors.newWorkStealingPool();

    2.2、new ThreadPoolExecutor()创建线程

    public ThreadPoolExecutor(int corePoolSize,
    int maximumPoolSize,
    long keepAliveTime,
    TimeUnit unit,
    BlockingQueue<Runnable> workQueue,
    ThreadFactory threadFactory,
    RejectedExecutionHandler handler)
    

    参数说明:

    参数含义解释
    corePoolSize该线程池中核心线程数最大值核心线程生命周期无限,即使空闲也不会死亡
    maximumPoolSize线程总数最大值任务队列满了以后当有新任务进来则会增加一个线程来处理新任务(线程总数<maximumPoolSize )
    keepAliveTime闲置超时时间当线程数大于核心线程数时,超过keepAliveTime时间将会回收非核心线程
    unitkeepAliveTime 的单位
    workQueue线程池中的任务队列*
    threadFactory为线程池提供创建新线程的线程工厂*
    RejectedExecutionHandler饱和策略抛出异常专用,当队列和最大线程池都满了之后的饱和策略。

    在这里插入图片描述

    2.2.1、拒绝策略

    ThreadPoolExecutor的饱和策略可以通过调用setRejectedExecutionHandler来修改。JDK提供了几种不同的RejectedExecutionHandler实现,每种实现都包含有不同的饱和策略:AbortPolicy、CallerRunsPolicy、DiscardPolicy和DiscardOldestPolicy。

    拒绝策略如下:

  • CallerRunsPolicy : 调用线程处理任务
  • AbortPolicy : 抛出异常
  • DiscardPolicy : 直接丢弃
  • DiscardOldestPolicy : 丢弃队列中最老的任务,执行新任务
  •         RejectedExecutionHandler rejected = null;//默认策略,阻塞队列满,则丢任务、抛出异常rejected = new ThreadPoolExecutor.AbortPolicy();//阻塞队列满,则丢任务,不抛异常rejected = new ThreadPoolExecutor.DiscardPolicy();//删除队列中最旧的任务(最早进入队列的任务),尝试重新提交新的任务rejected = new ThreadPoolExecutor.DiscardOldestPolicy();//队列满,不丢任务,不抛异常,若添加到线程池失败,那么主线程会自己去执行该任务rejected = new ThreadPoolExecutor.CallerRunsPolicy();

    总结: 就是被拒绝的任务,直接在主线程中运行,不再进入线程池。

http://www.lryc.cn/news/166263.html

相关文章:

  • 行业追踪,2023-09-14
  • 传输层协议--UDP
  • 微信会员卡开发流程
  • 《算法竞赛·快冲300题》每日一题:“点灯游戏”
  • 常见高级语言的输入与输出训练(一)
  • 恭喜!龙蜥获得 2023 大学生操作系统设计赛二等奖及特殊贡献奖
  • 中项系统集成项目管理2023上半年真题及解析
  • 实时显示当前文件夹下的文件大小,shell脚本实现
  • 7、Spring之依赖注入源码解析(下)
  • 图片码二次渲染绕过
  • 点评项目核心内容
  • 海外商城小程序为什么这么受欢迎?
  • Linux Day13 ---信号量
  • 《动手学深度学习 Pytorch版》 4.10 实战Kaggle比赛:预测比赛
  • jQuery补充
  • goaccess 日志分析 nginx
  • 认养一头牛———众筹+合伙人商业模式解析
  • 前端面试的话术集锦第 11 篇:高频考点(React和Vue两大框架)
  • 前端js下载zip文件异常问题解决
  • 深度学习面试八股文(2023.9.06)
  • Linux入门-网络基础|网络协议|OSI七层模型|TCP/IP五层模型|网络传输基本流程
  • docker系列(2) - 常用命令篇
  • Debian11安装MySQL8.0,链接Navicat
  • vue项目中使用特殊字体的步骤
  • 激光雷达检测负障碍物(附大概 C++ 代码)
  • 【每日一题】9.13 PING是怎么工作的?
  • 【Python百日进阶-Web开发-Peewee】Day279 - SQLite 扩展(四)
  • Postman接口压力测试 ---- Tests使用(断言)
  • nvue文件中@click.stop失效
  • 【微信小程序开发】宠物预约医疗项目实战-开发功能介绍