分布式与高并发(一)了解多线程的意义和使用

2023-11-07

了解多线程的意义和使用

什么是线程

并发与高并发

客户端向Tomcat发送请求,在Tomcat中存在多个个并发数,这个并发数由什么决定的。
并发:单位时间内能够同时处理的请求数。
默认情况下Tomcat可以支持的最大请求数是150,也就是同时支持150个并发。

影响服务器吞吐量的因素

硬件

CPU,内存,磁盘,网络

软件

最大化的利用硬件资源
线程数量、JVM内存分配大小、网络通信机制(BIO、NIO、AIO)、磁盘IO

线程数量如何提升服务端的并发数量

并发和并行

并行:指两个或多个事件在同一时刻发生。多核CPU,可以同时处理多个线程。
并发:指两个或多个事件在同一时间间隔内发生。单核CPU在一段时间内可以给通过时间片的切换完成对多线程的处理。

多线程的特点

  • 异步
  • 并行
    多线程:是对cpu剩余劳动力的压榨,是一种技术。
    异步:强调的是非阻塞编程,是一种编程模式(pattern),主要解决UI响应被阻塞的问题,可借助线程技术或者硬件本身的计算能力解决。
    并行:同样是对CPU剩余劳动力的压榨,但是基于多线程技术,它强调的是高效完成计算任务,而不是并发量。

举例:有两辆车,需要从A开到B

  1. 阻塞式编程:先开回去一辆,再回来开另一辆。
  2. 传统异步变成:将一辆车快递,开一辆车回去。注意,快递公司派件(回调)时我不一定已经开到B,如果需要本人签收,会比较麻烦。–通过这种回调进行异步变成的方法,没有办法编写符合逻辑思维顺序的代码。
  3. 基于多线程的异步编程:获得瞬间移动的超能力(CPU算力提升)以毫秒级的速度在两辆车之间进行切换驾驶。其中一辆车(主线程)上友车载电话,可以处理其他事情。–期间频繁的上下文切换,会造成额外损耗,造成反应能力比较差,只能开到60迈。
  4. 并行变成:获得分身能力。两个人驾驶两辆车。充分发挥CPU的功能,没有额外上下文切换。

Java中的线程

  • Runnable
public class RunnableDemo implements Runnable{
    @Override
    public void run() {
        Thread.sleep(1000);
        System.out.println("come on baby");
    }


    public static void main(String[] args) {
        RunnableDemo runnableDemo = new RunnableDemo();
        Thread thread = new Thread(runnableDemo);
        thread.start();
        System.out.println("hello");
    }
}
  • Thread(类似Runnable)
  • Callable/feture(带返回值)
public class CallableDemo implements Callable<String> {

    //线程的控制是由操作系统控制,不由Java程序控制
    @Override
    public String call() throws Exception {
        System.out.println("come on baby!");
        Thread.sleep(3000);
        return "SUCCESS";
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(1);
        CallableDemo callableDemo = new CallableDemo();
        Future<String> future = executorService.submit(callableDemo);
        System.out.println(future.get());   //线程阻塞
        System.out.println("hello");
    }

多线程使用情景

  1. 网络请求分发
  2. 文件导入
  3. 短信发送

注册时发送邮件
在这里插入图片描述

@postMapping("/sms/user")
public String register(User user) {
long start = System.currentTimeMillis();
userService.insert(user);
//异步
new Thread(()->{
	smsClient.sendSms("");
}).start() 
long end = System.currentTimeMillis();
return "SUCCESS" + (end - start);
}

在实际开发的时候使用线程池对线程进行管理。

 ExecutorService executorService = Executors.newFixedThreadPool(10);
@postMapping("/sms/user")
public String register(User user) {
long start = System.currentTimeMillis();
userService.insert(user);
//异步
executorService.submit(new Runnable(){
	@Override
	public void run(){
	smsClient.sendSms("");
	}
})
long end = System.currentTimeMillis();
return "SUCCESS" + (end - start);
}

线程的基础

线程的生命周期

阻塞:
WAITING
TIME_WAITING
BLOCKED
IO阻塞

Java的线程状态:

  1. 初始(NEW):新创建一个对象,但是还没有调用start()方法。
  2. 运行(RUNNABLE):Java线程中准备就绪(ready)和运行中(running)两种状态统称为“运行”。线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变成运行中状态(running)。
  3. 阻塞(BLOCKED):标识线程阻塞与锁。
  4. 等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或终端)。
  5. 超时等待(TIMED_WAITING):该状态与WAITING,它可以在指定的时间后自行返回。
  6. 终止(TERMINATED):表示线程已经执行完毕。

在这里插入图片描述
操作系统中的线程去除new和terminated状态,一个线程真实存在的状态只有:
ready:表示线程已经创建,正在等待系统调度分配CPU使用权。
running:表示线程获得了CPU使用权,正在进行运算。
waiting:便是线程等待(挂起),让出CPU资源给其他线程使用。
加上新建状态和死亡状态一共5种。

线程的启动

new Thread().start();	//启动一个线程
Thread t1 = new Thread();
t1.run();	//调用实例方法

实现原理:
首先Java调用Thread的start()方法,在start()方法中调用了JVM的start0()方法。jvm根据系统环境(例如:windows平台)调用os(操作系统)的创建线程方法create_thread然后调用线程:start_thread。
os中的线程调用jvm中的run方法:thread.run获取需要的run,而JVM需要去Java中调用run。
在这里插入图片描述

线程的终止

线程的终止:

  • 简单粗暴的方法:Thread.stop(),但是不推荐。原因:

    1. 调用stop()方法会立刻停止run()方法中剩余的所有工作,包括catch或finally语句中的,并抛出ThreadDeath异常(通常情况下此异常不需要显示的捕获),因此可能会导致清理性的工作得不到完成,如文件,数据库等的关闭。
    2. 调用stop()方法会立即释放该线程所吃用的锁,导致数据得不到同步,出现数据不一致的问题。
  • 标志位终止线程:

public class RunnableDemo extends Thread implements Runnable{
    @Override
    public void run() {
        while (!Thread.currentThread().isInterrupted()){
            System.out.println("come on baby");
        }
    }


    public static void main(String[] args) {
        RunnableDemo runnableDemo = new RunnableDemo();
        Thread thread = new Thread(runnableDemo);
        thread.start();
        System.out.println("hello");
        thread.interrupt(); //设置interrupt=true
    }
}
  • 使用Interceptor()中断线程

interrupt()的使用

但凡是让线程阻塞的机制,都抛出InterruptException异常
interrupt()方法并不像for循环语句中使用break语句那样干脆,马上就停止循环。调用interrupt()方法仅仅是在当前线程中打一个停止的标记,并不是真正的停止线程。
也就是说,线程中断并不会立即终止线程,而是通知目标线程,有人希望你终止。至于目标线程收到通知后会如何处理,则完全由目标线程自行决定(决定语句写在catch(InterruptException) 的语句中)。

所以Interrupt的作用:

  1. 设置一个共享变量的值true。
  2. 唤醒处于阻塞状态下的线程。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

分布式与高并发(一)了解多线程的意义和使用 的相关文章

随机推荐

  • Ajax

    jQuery Ajax 实例 全解析 jQuery确实是一个挺好的轻量级的JS框架 能帮助我们快速的开发JS应用 并在一定程度上改变了我们写JavaScript代码的习惯 废话少说 直接进入正题 我们先来看一些简单的方法 这些方法都是对jQ
  • 【js】根据给定的数组和属性从源数组中获取数据

    想从一个数组中 根据该数组的某个属性值 例如id 取出相对应的数据 可以参考下面的方法 getDataByGivenArray function sourceArray indexArray indexKey var array for v
  • 2.FreeRTOS系统任务调度简介及任务状态

    目录 一 基础知识 1 FreeRTOS 任务状态 1 运行态 2 就绪态 3 阻塞态 4 挂起态 二 任务调度简介 1 抢占式调度 2 时间片调度 3 协程式调度 一 基础知识 1 FreeRTOS 任务状态 FreeRTOS 中任务存在
  • 前端CSS文字阴影text-shadow记录

    前端CSS文字阴影text shadow记录 一 文字阴影
  • 当贝显示服务器生病,【当贝市场】电视盒子卡顿的三大原因

    原标题 当贝市场 电视盒子卡顿的三大原因 很多不明真相的网友在购买了电视盒子之后会出现同样的问题 家里的电视盒子越用越卡 尤其是在看直播节目的时候出现很明显的卡顿掉帧现象 可能你会问 家里的电视盒子越用越卡是不是跟网速有关 通过小编长时间的
  • mysql分表的3种方法

    参考 https blog csdn net czh500 article details 89735492 一 先说一下为什么要分表 一张的数据达到几百万时 你查询一次所花的时间会变多 如果有联合查询的话 我想有可能会死在那儿了 分表的目
  • S-DES的简单理解和实例

    S DES是一个供教学而非安全使用的加密算法 与DES的特性和结构类似 但它参数小 明文分组为8位 主密钥分组为10位 采用两轮选代 例题 采用手工方式使用 S DES用密钥 01111 11101 解密比特串 1010 0010 写出每个
  • 观察进程的内存占用情况

    概述 想必在linux上写过程序的同学都有分析进程占用多少内存的经历 或者被问到这样的问题 你的程序在运行时占用了多少内存 物理内存 通常我们可以通过top命令查看进程占用了多少内存 这里我们可以看到VIRT RES和SHR三个重要的指标
  • Go高级编程详解

    一 数据操作 1 读取用户的输入 我们如何读取用户的键盘 控制台 输入呢 从键盘和标准输入 os Stdin 读取输入 最简单的办法是使用 fmt 包提供的 Scan 和 Sscan 开头的函数 请看以下程序 示例 readinput1 g
  • sklearn实现支持向量机

    机器学习入门实验之支持向量机 简单实验 使用sklearn完成 代码如下 注 本文章主要是为方便自己以后复习所学内容而写 并不做详细介绍 支持向量机 这里是线性核 sklearn自带软间隔支持向量机 import pandas as pd
  • 用计算机数字语言研究中医理论,试论中医基础理论数字模型.pdf

    试论中医基础理论数字模型 pdf 维普资讯 知 盈 世界科学技术 中药现代化 中医现代化 医 学 课 堂 摘 要 中医基础理论研究的现代化是中医现代化的基础和前提 提出将中医学的基本概念进行 进制数字编码 根据中医原理和规律确定算法 建立数
  • macos 解决 Failed building wheel for xxx

    Failed building wheel for greenlet meinheld ujson 一 手动下载whl文件 二 xcode select install 三 多个版本MacOSX sdk pip install时可能会失败
  • 城市内涝积水监测预警系统的重要性

    一 系统概述 随着我国城镇化快速发展 城市建设产生的大量地面硬底化 大部分的降雨将形成地表径流 仅有少量雨水渗入地下 导致城市内涝等一系列问题 当前 全国多地发生洪涝 我国南北方全面进入主汛期 需要重点防治暴雨造成的城乡内涝 山体滑坡等安全
  • 【java】高并发之限流 RateLimiter使用

    1 概述 转载原文 高并发之限流 你可能知道高并发系统需要限流这个东西 但具体是限制的什么 该如何去做 还是模凌两可 我们接下来系统性的给它归个小类 希望对你有所帮助 google guava中提供了一个限流实现 RateLimiter 这
  • chmod函数

    int chmod const char pathname mode t mode 作用 修改文件的权限 参数 mode 需要修改的权限值 宏或者八进制数 返回值 成功 0 失败 1 include
  • 线性表顺序存储及相关操作(创建,插入,删除,遍历)

    线性表类型的定义 线性表是由同类数据元素构成的有序序列的线性结构 表中元素个数 n gt 0 称为线性表的长度 n 0时称为空表 在复杂线性表中 一个数据元素可以由若干个数据项 item 组成 这种情况下 常把数据元素称为记录 record
  • Linux 入门笔记(根据传智韩顺平整理的(一))

    开发步骤 1 Vi Hello java 2 输入i进入插入模式 3 输入esc 进入命令模式 4 输入 冒号 wq保存退出 q 退出不保存 5 编译Hello java gt javac Hello java 6 运行 java Hell
  • C++如何显示一个函数被调用的次数

    问题1 如何显示一个函数被调用的次数 使用static关键字 汉诺塔问题局部 void move char src char dest static int n 1 n具有全局寿命 但是局部可见 cout lt
  • 什么是漏洞扫描?

    首先什么是漏洞 国内外各种规范和标准中关于漏洞 也称脆弱性 英文对应Vulnerability 的定义很多 摘录如下 互联网工程任务组RFC4949 1 系统设计 部署 运营和管理中 可被利用于违反系统安全策略的缺陷或弱点 中国国家标准 信
  • 分布式与高并发(一)了解多线程的意义和使用

    了解多线程的意义和使用 什么是线程 并发与高并发 客户端向Tomcat发送请求 在Tomcat中存在多个个并发数 这个并发数由什么决定的 并发 单位时间内能够同时处理的请求数 默认情况下Tomcat可以支持的最大请求数是150 也就是同时支