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

java学习--多线程

多线程

在这里插入图片描述

了解多线程

​ 多线程是指从软件或者硬件上实现多个线程并发执行的技术。

​ 具有多线程能力的计算机因有硬件支持而能够在同一时间执行多个线程,提升性能。

并发和并行

  • 并行:在同一时刻,有多个指令在CPU上同时执行
  • 并发:在同一时刻,有多个指令在CPU上交替执行

进程和线程

进程:正在运行的软件

  • 独立性:进程是一个独立运行的基本单位,同时也是系统分配调度资源的独立单位。
  • 动态性:进程的实质就是程序的一次执行过程,动态产生,动态消亡。
  • 并发性:任何进程都可以和其他进程并发执行

线程:是进程中单个顺序控制流,是一条执行路径

  • 单线程:一个进程如果只有一条执行路径,则称为单线程程序
  • 多线程:一个进程如果有多条执行路径,则成为多线程程序

多进程的实现方案

  • 继承Thread类的方式进行实现
    • 定义一个类继承Thread类
    • 在定义的类中重写run()方法
    • 创建自定义类的对象
    • 启动线程
  • 实现Runable接口的方式实现
    • 自定义一个类实现Runable接口
    • 在自定义类中重写run()方法
    • 创建自定义对象
    • 创建Tread类对象,把自定义对象作为构造方法的参数
    • 启动线程
  • 利用Callable和Future接口方式实现
    • 定义一个类实现Callable接口
    • 在该类中重写call方法
    • 创建自定义类的对象
    • 创建Future的实现类FutureTask对象,把自定义类对象作为构造方法的参数
    • 创建Tread类的对象,把FutureTask对象最为构造方法的参数
    • 启动线程

三种方式的对比

优点缺点
实现Runnable,Callable接口扩展性强,实现该接口的同时还可以继承其他类编程相对复杂,不能直接使用Thread类中的方法
继承Thread类编程比较简单,可以直接使用Thread类中的方法可扩展性差,不能继承其他类

使用getName()获取当前正在执行现成的名称

使用setName()给当前线程设置名称,也可使用子类的带参构造方法设置名称

使用Thread的Sleep()方法 使得线程睡眠特定的时间

实现Runnable结构创建多线程程序的好处

  1. ​ 避免了单继承的局限性
    • 一个类只能继承一个类,自定义类继承了Thread类就不能继承其他类
    • 实现了Runnable接口,还可以继承其他类,实现其它接口
  2. 增强了程序的扩展性,降低了程序的耦合性
    • 实现了Runnable接口的方式,把设置线程任务和开启新线程进行了分离(解耦)
    • 实现类中,重写了run方法,用来设置线程任务
    • 创建Thread类对象,调用start方法,用来开启新的线程

线程安全问题

解决措施:

使用同步机制解决
方法一:同步代码块
syncheonized(对象){代码块
}
方法二:同步方法

使用步骤:

  • 把访问了共享数据的代码提取出来,放到一个方法中
  • 在方法上添加synchronized修饰符
  • 格式
修饰符 synchronized 返回值类型 方法名(参数列表){可能会出现安全问题的代码(访问了共享数据的代码)
}
线程池

线程池可以看成是一个池子,这个池子中存储很多个线程

系统创建一个线程的成本是很高的,因为他涉及到与操作系统的交互,当程序需要创建大量生存期很短暂的线程是,频繁的创建何晓辉线程对系统的资源消耗可能大于业务处理对线程的消耗。为了提高性能,我们可以采用线程池。

线程池在启动时,会创建大量空闲线程,当我们向线程池提价搜任务是,线程池就会启动一个线程来执行该任务。等待任务执行完毕,线程并不会死亡,而是咋次返回到线程池中称为空闲状态,等待哦下一次任务的执行。

线程池的设计思路

  1. 准备一个任务容器
  2. 一次性启动多个消费者线程
  3. 刚开始任务容器是空的,所有线程都在等待
  4. 知道一个外部线程向这个任务容器扔了一个“任务”,就会有一个消费者线程被唤醒
  5. 这个消费者线程取出任务,并执行任务,执行完毕后,继续等待下一次任务的到来
线程池-Executors默认线程池

概述:在开发中我们使用JDK中自带的线程池

我们可以使用Excutors中所提供的的静态方法来创建线程池

static ExcutorsService newCachedThreadPool()创建一个默认线程池

static newFixedThreadPool(int nThreads)创建一个指定最多线程数量的线程池

代码实现

ackage practise2.Exam2;import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;//static ExecutorsService new CachedThreadPool() 创建一个默认的线程池
//static newFixedThreadsPool(int nThreads) 创建一个指定最多线程数量的线程池
public class Exam1 {public static void main(String[] args) {//创建一个默认线程池对象,池子是空的,默认最多可以容纳int类型的最大值ExecutorService executorService= Executors.newCachedThreadPool();//Executors ---可以帮助我们创建线程池对象//ExecutorService ---可以帮助我们控制线程池executorService.submit(()->{System.out.println(Thread.currentThread().getName()+"在执行了");});executorService.submit(()->{System.out.println(Thread.currentThread().getName()+"在执行了");});executorService.shutdown();}
}
线程池-Executors创建指定上限的线程池

使用Executors中所提供的静态方法来创建线程池

static ExecutorsService newFixcedThreadPool(int nThread):创建一个指定最多线程数量的线程池

代码实现:

package practise2.Exam2;import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;//static ExecutorService newFixedThreadPool(int nThread):创建一个指定最多线程数量的线程池
public class Exam2 {public static void main(String[] args) {//参数不是初始值而是最大值ExecutorService executorService= Executors.newFixedThreadPool(10);ThreadPoolExecutor pool= (ThreadPoolExecutor) executorService;System.out.println(pool.getPoolSize()); //0executorService.submit(()->{System.out.println(Thread.currentThread().getName()+"在执行了");});executorService.submit(()->{System.out.println(Thread.currentThread().getName()+"在执行了");});System.out.println(pool.getPoolSize());//2//executorService.shutdown();}
}
线程池-ThreadPoolExecutor

创建线程池对象:

ThreadPoolExecutors threadPoolExecutor =new ThreadPoolExecutor(核心线程数连发,最大线程数量,空闲线程数量,空闲线程最大存活时间,任务队列,创建线程工厂,任务的拒绝策略);

代码实现

package practise2.Exam2;import pracise1.exam5.MyRunnable;import java.util.concurrent.*;public class Exam3 {public static void main(String[] args) {//参数一:核心线程数量//参数二:最大线程数//参数三:空闲线程最大存活时间//参数四:时间单位//参数五:任务队列//参数六:创建线程工厂//参数七:人物的拒绝策略ThreadPoolExecutor pool =new ThreadPoolExecutor(2,5,2, TimeUnit.SECONDS,new ArrayBlockingQueue<>(10), Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());pool.submit(new MyRunnable());pool.submit(new MyRunnable());pool.shutdown();}
}
线程池-参数详解

创建线程池对象

ThreadPoolExecutor threadPoolExecutor =new ThreadPoolExecutor(

核心线程数量,最大线程数量,空闲线程最大存活时间,任务队列,创建线程工厂,任务的拒绝策略

)

参数含义限制
参数一核心线程数量不能小于0
参数二最大线程数不能小于等于0,最大线程数大于等于核心线程数
参数三空闲线程最大存活空间不能小于0
参数四时间单位时间单位
参数五任务队列不能为null
参数六创建线程工厂不能为null
参数七人物的拒绝策略不能为null
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
线程池-非默认任务拒绝策略

RejectedExecutionHandler是jdk提供的一个任务拒绝策略接口,他下面存在4个子类。

ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。是默认的策略。
ThreadPoolExecutor.DiscardPolicy: 丢弃任务,但是不抛出异常 这是不推荐的做法
ThreadPoolExecutor.DiscardOldestPolicy: 抛弃队列中等待最久的任务 然后把当前任务加入队列中。
ThreadPoolExecutor。CallerRunsPolicy: 调佣任务的run()方法绕过线程池直接执行

注:明确线程池对多可执行的任务数=队列容量+最大线程数

package practise2.Exam2;import java.util.concurrent.*;public class Exam {public static void main(String[] args) {
//        ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor(1,3,20,
//                TimeUnit.SECONDS,new ArrayBlockingQueue<>(1),
//                Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());//提交5个任务,而该线程池最多可以处理4个任务,当我们使用ABortPOlicy这个任务处理策略是后,就会抛出异常ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor(1,3,20,TimeUnit.SECONDS,new ArrayBlockingQueue<>(1),Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardOldestPolicy());//提交了5个任务for (int i = 0; i < 5; i++) {//定义一个变量,来制定当前执行的任务,这个变量需要被final修饰final int y=i;threadPoolExecutor.submit(()->{//System.out.println(Thread.currentThread().getName()+"------>>执行了任务");System.out.println(Thread.currentThread().getName()+"---->>执行了任务"+y);});}}
}
package practise2.Exam2;import java.util.concurrent.*;public class Exam5 {public static void main(String[] args) {ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor(1,3,20, TimeUnit.SECONDS,new ArrayBlockingQueue<>(1),Executors.defaultThreadFactory(),new ThreadPoolExecutor.CallerRunsPolicy());//提交五个任务for (int i = 0; i < 5; i++) {threadPoolExecutor.submit(()->{System.out.println(Thread.currentThread().getName()+"---->>执行了任务");});}}
}

通过控制台的输出,我们可以看次策略没有通过线程池中得到线程执行任务,而是直接调用任务的run()方法绕过线程池直接执行。

原子性

volatile-问题

代码分析:


volatile解决
以上案例出现的问题:

当A线程修改了共享数据时,B线程没有及时获取道最新的值,如果还在使用原先的值,就会出现问题。

  1. 堆内存是唯一的,每一个线程都有自己的线程栈
  2. 每一个线程在使用堆内存里面的变量时,都会先拷贝一份到变量的副本中
  3. 在线程中,每一次使用是从变量的副本中获取的

volatile关键字:强制线程在每一次使用时,都会看一下公共区域最新的值。

public class Money {public static volatile int money=100000;
}
public class MyThread1 extends Thread{@Overridepublic void run() {while (Money.money==100000){}System.out.println("结婚基金已经不是十万了");}
}
public class MyThread2 extends Thread{@Overridepublic void run() {try {Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}Money.money=90000;}
}
public class Demo {public static void main(String[] args) {MyThread1 myThread1=new MyThread1();myThread1.setName("小垃圾");myThread1.start();MyThread2 myThread2=new MyThread2();myThread2.setName("小趴菜");myThread2.start();}}
synchronized解决
  1. 线程获得锁
  2. 清空变量副本
  3. 拷贝共享最新的值到变量副本中
  4. 执行代码
  5. 将修改后变量副本中的值赋值给共享数据
  6. 释放锁

代码实现


原子性

概述:在一次操作或者多次操作中,要么所有的操作全部都得到了执行并且不会受到任何因素的干扰而中断,要么所有的操作都不执行,多个操作是一个不可分割的整体。

Volatile关键字不能保证原子性

解决方案:我们可以给count++操作添加锁,那么count++操作就是临界区中的代码,临界区中的代码一次只能被一个线程去执行,所以count++就变成了的原子操作。


原子性—AtomicInteger

概述:java从JDK1.5开始提供了java.uyil.concurrent.atomic包(简称Atomic包),这个包中的原子提供了一种用法简单,性能高效,线程安全地根新一个变量的方式,因为变量的类型有很多个,所以在Atomic包中一共提供了13个类,属于4种类型的原子更新方式,分别是:

原子更新基本类型,原子更新数组,原子更新引用和原子更行属性(字段)

使用原子的方式甘心基本类型,使用原子的方式更新基本类型Atomic包提供了一下3个类:

AtomicBoolean:原子更新布尔类型

AtomicInteger:原子更新整型

AtomicLong:原子更新长整型

以上三个类提供的方法几乎一模一样,以AtomicInteger为例讲解

public AtomicInteger(); 	//初始化一个默认值为0的原子型Integer
public AtomicInteger(int initialValue):	//初始化一个指定值的原子型Integerint get();								//获取值
int getAndIncrement();					//以原子的方式将当前值加1,注意,这里返回的是自增前的值
int incrementAndGet();					//以原子的方式将当前值加1,注意,这里返回的是自增前的值
int addAndGet(int data):				//以原子的方式将输入的数值与示例中的值(AtomicInteger里的value)相加,并返回结果。
int getandSet(int value):				//以原子方式设置为newValur的值,并返回旧值

代码实现:


AtomicInteger-内存解析

AtomicInteger原理:

自旋锁+CAS算法

CAS算法:

有三个操作数(内存值V,旧的预期值A,要修改的值B)

当旧的预期值A==内存值 此时修改成功,将V改为B

当旧的预期值A!=内存值,此时修改失败,不做任何操作

并重新获取现在的最新值(这个重新获取的动作就是自旋)

AtomicInteger-源码解析
代码实现:

源码解析

乐观锁和悲观锁

synchronized和CAS的区别

相同点:

​ 在多线程的情况下,都可以保证共享数据的安全性

不同点:

synchronized总是从最坏的角度出发,认为每次获取数据的时候,别人都有可能修改。所以在每次操作共享数据之前,都会上锁。(悲观锁)

cas是从乐观的角度出发,假设每次获取数据别人都不会修改,所以不会上锁,只不过在修改共享数据的时候,会检查一下。

如果别人修改过,则获取最新数据。

如果别人没有修改过,那么我们直接修改共享数据的值(乐观锁)

并发工具类

并发 工具类-Hashtable
Hashtable出现的原因:

​ 在集合类中HashMap是比较常用的集合类对象,但是HashMap是现成不安全的(多线程环境下可能会存在问题)。为了保证数据得到安全性我们可以使用Hashtable,但是Hashtable的效率低下。

代码实现:


并发工具类-ConcurrentHashMap基本使用
ConcurrentHashMap出现的原因

​ 在集合类中HashMap是比较常用的集合对象,但是hashMap是线程不安全的多线程环境下可能会存在的问题)。为了保证数据的安全性我们可以使用Hashtable,但是Hashtable的效率低下,基于以上两个原因我们可以使用JDK1.5以后提供的ConcurrentHashMap。

体系结构

ConcurrentHashMap

Map接口

  1. HashMap
  2. Hashtable
  3. TreeMap
  4. ConcurrentMap
总结:
  1. HashMap是线程不安全的,多线程环境下有数据安全问题
  2. hashtable 是线程安全的,但是会将整张表锁起来,效率低下‘
  3. ConcurrentHashMap也是线程安全的,效率高,在JDK7和JDK8中,底层原理不同

相关文章:

java学习--多线程

多线程 了解多线程 ​ 多线程是指从软件或者硬件上实现多个线程并发执行的技术。 ​ 具有多线程能力的计算机因有硬件支持而能够在同一时间执行多个线程&#xff0c;提升性能。 并发和并行 并行&#xff1a;在同一时刻&#xff0c;有多个指令在CPU上同时执行并发&#xff1…...

90后阿里P7技术专家晒出工资单:狠补了这个,真香...

最近一哥们跟我聊天装逼&#xff0c;说他最近从阿里跳槽了&#xff0c;我问他跳出来拿了多少&#xff1f;哥们表示很得意&#xff0c;说跳槽到新公司一个月后发了工资&#xff0c;月入5万多&#xff0c;表示很满足&#xff01;这样的高薪资着实让人羡慕&#xff0c;我猜这是税后…...

2023美赛C题:Wordle筛选算法

Wordle 规则介绍 Wordle 每天会更新一个5个字母的单词&#xff0c;在6次尝试中猜出单词就算成功。每个猜测必须是一个有效的单词&#xff08;不能是不能组成单词的字母排列&#xff09;。 每次猜测后&#xff0c;字母块的颜色会改变&#xff0c;颜色含义如下&#xff1a; 程…...

SpringBoot 集成 Kafka

SpringBoot 集成 Kafka1 安装 Kafka2 创建 Topic3 Java 创建 Topic4 SpringBoot 项目4.1 pom.xml4.2 application.yml4.3 KafkaApplication.java4.4 CustomizePartitioner.java4.5 KafkaInitialConfig.java4.6 SendMessageController.java5 测试1 安装 Kafka Docker 安装 Kafk…...

OpenCV 图像金字塔算子

本文是OpenCV图像视觉入门之路的第14篇文章&#xff0c;本文详细的介绍了图像金字塔算子的各种操作&#xff0c;例如&#xff1a;高斯金字塔算子 、拉普拉斯金字塔算子等操作。 高斯金字塔中的较高级别&#xff08;低分辨率&#xff09;是通过先用高斯核对图像进行卷积再删除偶…...

【自学Linux】Linux一切皆文件

Linux一切皆文件 Linux一切皆文件教程 Linux 中所有内容都是以文件的形式保存和管理的&#xff0c;即一切皆文件&#xff0c;普通文件是文件&#xff0c;目录是文件&#xff0c;硬件设备&#xff08;键盘、监视器、硬盘、打印机&#xff09;是文件&#xff0c;就连套接字&…...

CUDA C++扩展的详细描述

CUDA C扩展的详细描述 文章目录CUDA C扩展的详细描述CUDA函数执行空间说明符B.1.1 \_\_global\_\_B.1.2 \_\_device\_\_B.1.3 \_\_host\_\_B.1.4 Undefined behaviorB.1.5 __noinline__ and __forceinline__B.2 Variable Memory Space SpecifiersB.2.1 \_\_device\_\_B.2.2. \_…...

为什么重写equals必须重写hashCode

关于这个问题&#xff0c;看了网上很多答案&#xff0c;感觉都参差不齐&#xff0c;没有答到要点&#xff0c;这次就记录一下&#xff01; 首先我们为什么要重写equals&#xff1f;这个方法是用来干嘛的&#xff1f; public boolean equals &#xff08;Object object&#x…...

< 每日小技巧:N个很棒的 Vue 开发技巧, 持续记录ing >

每日小技巧&#xff1a;6 个很棒的 Vue 开发技巧&#x1f449; ① Watch 妙用> watch的高级使用> 一个监听器触发多个方法> watch 监听多个变量&#x1f449; ② 自定义事件 $emit() 和 事件参数 $event&#x1f449; ③ 监听组件生命周期常规写法hook写法&#x1f44…...

数据结构与算法之二分查找分而治之思想

决定我们成为什么样人的&#xff0c;不是我们的能力&#xff0c;而是我们的选择。——《哈利波特与密室》二分查找是查找算法里面是很优秀的一个算法&#xff0c;特别是在有序的数组中&#xff0c;这种算法思想体现的淋漓尽致。一.题目描述及其要求请实现无重复数字的升序数组的…...

训练自己的中文word2vec(词向量)--skip-gram方法

训练自己的中文word2vec&#xff08;词向量&#xff09;–skip-gram方法 什么是词向量 ​ 将单词映射/嵌入&#xff08;Embedding&#xff09;到一个新的空间&#xff0c;形成词向量&#xff0c;以此来表示词的语义信息&#xff0c;在这个新的空间中&#xff0c;语义相同的单…...

ubuntu系统环境配置和常用软件安装

系统环境 修改文件夹名称为英文 参考链接 export LANGen_US xdg-user-dirs-gtk-update 常用软件安装 常用工具 ping 和ifconfig工具 sudo apt install -y net-tools inetutils-ping 截图软件 sudo apt install -y net-tools inetutils-ping flameshot 录屏 sudo apt-get i…...

【1139. 最大的以 1 为边界的正方形】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 给你一个由若干 0 和 1 组成的二维网格 grid&#xff0c;请你找出边界全部由 1 组成的最大 正方形 子网格&#xff0c;并返回该子网格中的元素数量。如果不存在&#xff0c;则返回 0。 示例 1&#…...

windows11安装sqlserver2022报错

window11安装SQL Server 2022 报错 糟糕… 无法安装SQL Server (setup.exe)。此 SQL Server安装程序介质不支持此OS的语言&#xff0c;或没有SQL Server英语版本的安装文件。请使用匹配的特定语言SQL Server介质;或安装两个特定语言MUI&#xff0c;然后通过控制面板的区域设置…...

Python快速上手系列--日志模块--详解篇

前言本篇主要说说日志模块&#xff0c;在写自动化测试框架的时候我们就需要用到这个模块了&#xff0c;方便我们快速的定位错误&#xff0c;了解软件的运行情况&#xff0c;更加顺畅的调试程序。为什么要用到日志模块&#xff0c;直接print不就好了&#xff01;那得写多少print…...

【THREE.JS学习(1)】绘制一个可以旋转、放缩的立方体

学习新技能&#xff0c;做一下笔记。在使用ThreeJS的时候&#xff0c;首先创建一个场景const scene new THREE.Scene();接着&#xff0c;创建一个相机其中&#xff0c;THREE.PerspectiveCamera&#xff08;&#xff09;四个参数分别为&#xff1a;1.fov 相机视锥体竖直方向视野…...

数仓实战 - 滴滴出行

项目大致流程&#xff1a; 1、项目业务背景 1.1 目的 本案例将某出行打车的日志数据来进行数据分析&#xff0c;例如&#xff1a;我们需要统计某一天订单量是多少、预约订单与非预约订单的占比是多少、不同时段订单占比等 数据海量 – 大数据 hive比MySQL慢很多 1.2 项目架…...

python虚拟环境与环境变量

一、环境变量 1.环境变量 在命令行下&#xff0c;使用可执行文件&#xff0c;需要来到可执行文件的路径下执行 如果在任意路径下执行可执行文件&#xff0c;能够有响应&#xff0c;就需要在环境变量配置 2.设置环境变量 用户变量&#xff1a;当前用户登录到系统&#xff0c;…...

BeautifulSoup文档4-详细方法 | 用什么方法对文档树进行搜索?

4-详细方法 | 用什么方法对文档树进行搜索&#xff1f;1 过滤器1.1 字符串1.2 正则表达式1.3 列表1.4 True1.5 可以自定义方法2 find_all()2.1 参数原型2.2 name参数2.3 keyword 参数2.4 string 参数2.5 limit 参数2.6 recursive 参数3 find()4 find_parents()和find_parent()5…...

初识Tkinter界面设计

目录 前言 一、初识Tkinter 二、Label控件 三、Button控件 四、Entry控件 前言 本文简单介绍如何使用Python创建一个界面。 一、初识Tk...

软件测试面试题中的sql题目你会做吗?

目录 1.学生表 2.一道SQL语句面试题&#xff0c;关于group by表内容&#xff1a; 3.表中有A B C三列,用SQL语句实现&#xff1a;当A列大于B列时选择A列否则选择B列&#xff0c;当B列大于C列时选择B列否则选择C列 4. 5.姓名&#xff1a;name 课程&#xff1a;subject 分数&…...

VS实用调试技巧

一.什么是BUG&#x1f41b;Bug一词的原意是虫子&#xff0c;而在电脑系统或程序中隐藏着的一些未被发现的缺陷或问题&#xff0c;人们也叫它"bug"。这是为什么呢&#xff1f;这就要追溯到一个程序员与飞蛾的故事了。Bug的创始人格蕾丝赫柏&#xff08;Grace Murray H…...

通俗易懂理解三次握手、四次挥手(TCP)

文章目录1、通俗语言理解1.1 三次握手1.2 四次挥手2、进一步理解三次握手和四次挥手2.1 三次握手2.2 四次挥手1、通俗语言理解 1.1 三次握手 C:客户端 S&#xff1a;服务器端 第一次握手&#xff1a; C&#xff1a;在吗&#xff1f;我要和你建立连接。 第二次握手&#xff…...

1.1 什么是并发

1.1 什么是并发 并发&#xff1a;指两个或更多独立的活动同时发生。并发在生活中随处可见。我们可以一边走路一边说话&#xff0c;也可以两只手同时做不同的动作。 1.1.1 计算机系统中的并发 当我们提到计算机术语的“并发”&#xff0c;指的是在单个系统里同时执行多个独立…...

万字讲解你写的代码是如何跑起来的?

今天我们来思考一个简单的问题&#xff0c;一个程序是如何在 Linux 上执行起来的&#xff1f; 我们就拿全宇宙最简单的 Hello World 程序来举例。 #include <stdio.h> int main() {printf("Hello, World!\n");return 0; } 我们在写完代码后&#xff0c;进行…...

034.Solidity入门——21不可变量

Solidity 中的不可变量是在编译时就被确定的常量&#xff0c;也称为常量变量&#xff08;constant variable&#xff09;或只读变量&#xff08;read-only variable&#xff09;。这些变量在定义时必须立即初始化&#xff0c;并且在整个合约中都无法被修改&#xff0c;可以在函…...

Vulnhub 渗透练习(四)—— Acid

环境搭建 环境下载 kail 和 靶机网络适配调成 Nat 模式&#xff0c;实在不行直接把网络适配还原默认值&#xff0c;再重试。 信息收集 主机扫描 没扫到&#xff0c;那可能端口很靠后&#xff0c;把所有端口全扫一遍。 发现 33447 端口。 扫描目录&#xff0c;没什么有用的…...

C++ 在线工具

online编译器https://godbolt.org/Online C Compiler - online editor (onlinegdb.com) https://www.onlinegdb.com/online_c_compilerC Shell (cpp.sh) https://cpp.sh/在线文档Open Standards (open-std.org)Index of /afs/cs.cmu.edu/academic/class/15211/spring.96/wwwC P…...

使用MMDetection进行目标检测、实例和全景分割

MMDetection 是一个基于 PyTorch 的目标检测开源工具箱&#xff0c;它是 OpenMMLab 项目的一部分。包含以下主要特性&#xff1a; 支持三个任务 目标检测&#xff08;Object Detection&#xff09;是指分类并定位图片中物体的任务实例分割&#xff08;Instance Segmentation&a…...

使用ThreadLocal实现当前登录信息的存取

有志者&#xff0c;事竟成 文章持续更新&#xff0c;可以关注【小奇JAVA面试】第一时间阅读&#xff0c;回复【资料】获取福利&#xff0c;回复【项目】获取项目源码&#xff0c;回复【简历模板】获取简历模板&#xff0c;回复【学习路线图】获取学习路线图。 文章目录一、使用…...

南京哪家网络公司做网站优化好/关键词优化排名平台

C中的IO类(iostream, fstream, stringstream)小结 参考网址&#xff1a;https://blog.csdn.net/stpeace/article/details/44763009 以前学习C的时候&#xff0c; 总是囫囵吞枣地理解cin, cout等东东&#xff0c; 最近又在复习C, 复习到IO类这一章节的时候&#xff0c; 有点感…...

论述网站开发建设的一般流程/发稿网

HoloLens可以让我们在真实世界中看到全息图像内容。但是它本质上还是一台Windows 10设备&#xff0c;这意味着HoloLens可以以2D应用形式运行Windows Store里的大部分UWP应用。 目标平台设为Windows.Universal Targeting Windows.Universal 微软过去几年平台一直在变革&#xff…...

沧州市任丘建设局网站/百度如何购买关键词

如何手写一个过滤器呢。假设我现在需要一个计时过滤器&#xff0c;我想把每一次调用服务锁花费的时间打印到控制台&#xff0c;我该怎么做呢&#xff1f; ####拦截机制有三种&#xff1a; ######1. 过滤器&#xff08;Filter&#xff09;能拿到http请求&#xff0c;但是拿不到处…...

公司网站如何建设教程/搜索引擎营销的过程

本着“以教带学&#xff0c;Learning by Doing”的想法&#xff0c;我于上周加入了Bob组织的HiBlock区块链技术布道群。这个群可不太好混&#xff0c;群规要求每个成员必需每周有输出&#xff0c;连续两次交白卷就要被踢出群。 在这样的压力之下&#xff0c;我决定开一个新坑&a…...

博客网站开发毕设/网站建设公司好

许多shopee卖家在开店之初很容易陷入订单短缺的境地&#xff0c;他们甚至没有货物流通&#xff0c;造成这种情况的原因极有可能是选择的产品有问题&#xff0c;这边突出了选品的重要性&#xff0c;那么shopee选品的分类应该如何选择&#xff1f;首先我们了解到shopee主要面向的…...

网站开发基于百度地图/教育培训机构网站

作为多用户操作系统&#xff0c;每一个登录的用户都会默认在 %USERPROFILE%\Local Settings\ 创建一个与登录名同名的目录&#xff0c;用来保存我的文档、桌面、收藏夹、应用程序设置等数据。但用户个人配置文件默认保存在系统分区。因为各种原因要重新安装操作系统&#xff0c…...