《微服务实战》 第一章 Java线程池技术应用

news2024/11/20 1:43:49

前言

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

1、Java创建线程方式回顾

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

public class ThreadTest extends Thread{
    @Override
    public 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{

    @Override
    public 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() {
            @Override
            public 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() {
            //匿名类
            @Override
            public 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{
    @Override
    public void run() {
        log.info("统计销量");
    }

    public static void main(String[] args) {
        Thread thread = new Thread() {
            @Override
            public void run() {
                log.info("Hello world");
            }
        };
        thread.start();
    }
}

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

public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            @Override
            public 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> {
        @Override
        public 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.coloradmin.cn/o/495700.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【python】keras包:深度学习( MLP多层感知器 Multi-Layer Perceptron)

MLP多层感知器 Multi-Layer Perceptron Part 1. 算法逻辑 实现经典问题——如何通过图像区分猫和狗 神经网络&#xff1a;建立模型&#xff0c;模仿人的思考机制 将“机器学习_逻辑回归”按照神经元的逻辑&#xff0c;组成逻辑网络。 解释&#xff1a; 假设自变量x[]和应变…

档案库房建设需要遵守的一些规定

各单位在建设档案室时需要对照《机关档案管理规定》《档案馆建筑设计规范》关于档案库房的相关标准&#xff0c;对库房的位置、面积、承重、安全等方面进行全面考虑&#xff0c;建设符合国家规定的档案库房。 档案库房建设需要遵守什么规定&#xff1f; 一、《机关档案管理规定…

Transformer的位置编码

1. 什么是位置编码&#xff0c;为什么要使用位置编码 简单来说位置编码就是给一个句子中的每个token一个位置信息&#xff0c;通过位置编码可以明确token的前后顺序关系。 对任何语言来说&#xff0c;句子中词汇的顺序和位置都是非常重要的。它们定义了语法&#xff0c;从而定…

DP(9)--插头DP

DP(9)--插头DP /* Mondriaan’s Dream题目大意&#xff1a;在 N*M 的棋盘内铺满 1*2 或 2*1 的多米诺骨牌&#xff0c;求方案数。 砖只有横放和竖放两种状态&#xff0c;把横放记为两个0&#xff0c;竖放记为上1下0&#xff0c;逐格DP&#xff0c;每次无论前一格…

Kali Linux 配置动态/静态 IP

[笔者系统版本] [Kali]: Kali Linux 2023.1 [Kernel]: kernel 6.1.0 [Desktop]: Xfce 4.18.1 1. Kali Linux 配置动态 IP (1). 首先查看网卡接口名称。 (2). 编辑网络接口配置文件。 (3). 网络接口配置文件的默认内容是这样的。 (4). 新增配置内容如下&#xff1b; 指定网卡…

ChatGPT :十几个国内免费可用 ChatGPT 网页版

前言 ChatGPT&#xff08;全名&#xff1a;Chat Generative Pre-trained Transformer&#xff09;&#xff0c;美国OpenAI 研发的聊天机器人程序 &#xff0c;于2022年11月30日发布 。ChatGPT是人工智能技术驱动的自然语言处理工具&#xff0c;它能够通过理解和学习人类的语言…

浅析智慧充电桩云平台的技术设计方案

自从我国提出“新基建”以来&#xff0c;充电基础设施产业也成为行业的话题与关注焦点。据数据统计&#xff0c;2021年&#xff0c;中国新能源汽车保有量达到784万辆&#xff0c;预计2025年&#xff0c;中国新能源汽车保有量达到2672万辆&#xff0c;2025年充电桩数量将达到654…

SwiftUI 新 Alert 弹出窗口帮你实现文本输入之梦

概览 小伙伴们都知道&#xff0c;弹出 Alert 不能包含文本输入框是 SwiftUI 的阿喀琉斯之踵(Achilles’ Heel) 。当然&#xff0c;这说的有些夸张了。&#x1f609; 不过&#xff0c;Alert 不能包含 TextField 在某些情况下着实不方便。于是乎&#xff0c;从 SwiftUI 3.0&…

[pgrx开发postgresql数据库扩展]附1.存储过程的优缺点与数据库扩展函数

俗话说&#xff1a;天下大势&#xff0c;分久必合&#xff0c;合久必分。 最早的软件系统开发&#xff0c;讲究的就是一个全栈——在最早期的桌面软件时代&#xff0c;数据、用户界面和业务逻辑是完全混在一起的&#xff0c;讲究的就是一个一体化……那个年代也诞生了大量的码农…

MySQL基础(三)基本的SELECT语句

1. SQL概述 1.1 SQL背景知识 1946 年&#xff0c;世界上第一台电脑诞生&#xff0c;如今&#xff0c;借由这台电脑发展起来的互联网已经自成江湖。在这几十年里&#xff0c;无数的技术、产业在这片江湖里沉浮&#xff0c;有的方兴未艾&#xff0c;有的已经几幕兴衰。但在这片浩…

同步辐射散射数据处理:从测量到分析的全流程解析

同步辐射散射数据处理&#xff1a;从测量到分析的全流程解析 同步辐射&#xff08;Synchrotron radiation&#xff0c;SR&#xff09;是指粒子在强磁场中受到加速或转向时所放出的辐射。这种辐射是一种非常强烈、具有非常高能量和亮度的电磁辐射。同步辐射散射&#xff08;Sync…

怎么控制别人的电脑屏幕?

为什么需要控制别人的屏幕&#xff1f; 我们不可避免地会遇到一些情况&#xff0c;比如我们需要为我们的朋友、同事或家人提供有关 IT 相关问题的帮助&#xff0c;如果他们不知道它该怎么处理这些问题该怎么办呢&#xff1f; 这时&#xff0c;我们可能需要用我们的电脑…

聊点技术 | 全新功能,让Bonree ONE变得更强

4月21日&#xff0c;博睿数据ONE有引力2023春季产品发布会圆满落幕&#xff0c;Bonree ONE 2023春季正式版正式发布&#xff0c;带来更轻、更强、更智能的一体化智能可观测平台。 全新功能&#xff0c;让Bonree ONE变得更强 本文作者 产品经理高天明、产品经理吴学飞、产品经…

Mysql监控账号创建【Prometheus】

Mysql的监控采用一个使用mysqld_exporter启动多个进程来实现监控多个mysql实例。 代理部署架构如下 1&#xff0c;创建数据库监控账号 create user 监控账号mysqld_exporter主机的IP identified by 监控密码 with max_user_connections 10; 2&#xff0c;权限授予 grant pr…

KDSL-82-1000A大电流发生器

一、产品简介 KDSL-82-1000A大电流发生器&#xff08;简称升流器&#xff09;&#xff0c;我公司自行研制开发的测试设备&#xff0c;它集国内外同类产品的优点于一身&#xff0c;采用数控技术&#xff0c;抗干扰能力强&#xff0c;和上一代升流器相比&#xff0c;由于采用低功…

NetSuite .id的用法

我们必须认清一个事实&#xff0c;NetSuite Saved Search是一个被封装化的SQL查询工具。在NetSuite的早期版本中&#xff0c;可以利用Formula字段做很多SQL语句上的灰色应用。但是慢慢的&#xff0c;灰色应用范围被压缩了。目前只剩下一个“.id”的应用了。 今朝我们就谈谈.id…

网络管理员优化提高网络性能需要关注的三个指标

网络管理员有一个主要责任&#xff1a;确保其网络的正常运行时间&#xff0c;同时不影响网络性能。然而&#xff0c;随着现代可部署解决方案通过传统的网络架构&#xff0c;这说起来容易做起来难。尽管现代解决方案在效率方面绝对比传统解决方案更上一层楼&#xff0c;但它们也…

任务态相关的一些知识总结

静息态的数据处理现在都比较简单了&#xff0c;因为有了fmriprep和qsiprep流程工具&#xff0c;没有特别的难度。 而关于任务态&#xff0c;则有一些独特的处理方式&#xff0c;因为最近要做任务态的数据分析&#xff0c;所以学习一下。 先学习下R的4个重输出函数&#xff1a;…

更懂业务的数智平台,应对数智化转型的“千变万化”

本文作者 跨界的申斯基 毫无疑问&#xff0c;随着数智化转型的加速&#xff0c;越来越多的企业正在把数智化战略提升到一个全新的高度&#xff0c;转型的进程也正从“浅层次”的数智化走向“深层次”数智化的阶段。 这也让企业的数智化转型进入到了一个全新的阶段&#xff0c;…

windows权限维持之shift后门

原理&#xff1a;沾滞键的目的是为了帮助那些按键有困难的人设计的&#xff0c;在Windows系统下连续按5次shift键后&#xff0c;系统就会执行C:\Windows\System32下的sethc.exe&#xff0c;也就是启用了沾滞键&#xff0c;但是当我们将shell.exe文件把sethc.exe文件通过更改名称…