java面试(多线程)

news2024/11/20 6:13:08

线程和进程的区别

程序由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至CPU,数据加载至内存。在指令运行过程中还需要用到磁盘,网络等设备。进程就是用来加载指令,管理内存,管理IO的。
当一个程序被运行,从磁盘加载这个程序的代码至内存,这时就开启了一个进程。
一个线程就是一个指令流,将指令流中的一条条指令以一定的顺序交给CPU执行
一个进程之内可以分为一到多个线程
二者对比:

  1. 进程是正在运行程序的实例,进程中包含了线程,每个线程执行不同的任务
  2. 不同的进程使用不同的内存空间,在当前进程下的所有线程可以共享内存空间
  3. 线程更轻量,线程上下文切换成本一般上要比进程上下文切换低(上下文切换指的是从一个线程切换到另一个线程)

并行和并发的区别

单核CPU

  1. 单核CPU下线程实际还是串行执行的
  2. 操作系统中有一个组件叫做任务调度器,将cpu的时间片(windows下时间片最小约为15ms)分给不同的程序使用,只是由于cpu在线程间(时间片很短)的切换非常快,人类感觉是同时运行的
  3. 总结为一句话就是:微观串行,宏观并行
  4. 一般会将这种线程轮流使用CPU的做法叫做并发(concurrent)

多核CPU

每个核(core)都可以调度运行线程,这时候线程可以是并行的
对比
并发(concurrent)是同一时间应对(dealing with)多件事情的能力
并行(parallel)是同一时间动手做(doing)多件事情的能力
在这里插入图片描述

创建线程的方式

共有四种方式可以创建线程,分别是:

  1. 继承Thread类
  2. 实现runnable接口
  3. 实现callable接口
  4. 线程池创建线程

继承Thread类

在这里插入图片描述

实现runnable接口

在这里插入图片描述

实现Callable接口

在这里插入图片描述

线程池创建线程

在这里插入图片描述

使用runnable和callable创建线程的区别

  1. Runnable接口run方法没有返回值
  2. callable接口call方法有个返回值,是个泛型,和Future,FutureTask配合可以用来获取异步执行的效果
  3. Callable接口的call()方法允许抛出异常;而Runnable接口的run()方法的异常只能在内部消化,不能继续上抛

线程的run()和srart()有什么区别

start()用来启动线程,通过该线程调用run方法执行run方法中定义的逻辑代码。start方法只能被调用一次。
run()封装了要被线程执行的代码,可以被调用多次

线程包括哪些状态,状态之间是如何变化的

线程的状态可以参考JDK中Thread类中的枚举State

在这里插入图片描述
在这里插入图片描述

线程包括哪些状态

  1. 新建(NEW)
  2. 可运行(RUNNABLE)
  3. 阻塞(BLOCKED)
  4. 等待(WAITING)
  5. 时间等待(TIMED_WAITING)
  6. 终止(TREMINATED)

线程之间的状态是如何变化的

  1. 创建线程对象是新建状态
  2. 调用了start()方法转变为可执行状态
  3. 线程获取到了CPU的执行权,执行结束是终止状态
  4. 在可执行状态的过程中,如果没有获取CPU的执行权,可能会切换其他状态
    1. 如果没有获取锁(synchronized或lock)进入阻塞状态,获得锁再切换为可执行状态
    2. 如果线程调用了wait()方法进入等待状态,其他线程调用notify()唤醒后可切换为可执行状态
    3. 如果线程调用了sleep()方法,进入计时等待状态,到时间后可切换为可执行状态

新建T1,T2,T3三个线程,如何保证他们按顺序执行

可以使用线程中的join方法解决

notify和notifyAll有什么区别

  1. notifyAll:唤醒所有wait的线程
  2. notify:只随机唤醒一个wait线程

wait和sleep方法的不同

  1. 共同点:
    1. wait,wait(long),sleep(long)的效果都是让当前线程放弃CPU的使用权,进入阻塞状态
  2. 不同点:
    1. 方法归属不同
      1. sleep(long)是Thread的静态方法
      2. 而wait,wait(long)都是Object的成员方法,每个对象都有
    2. 醒来时机不同
      1. 执行sleep(long)和wait(long)的线程都会在等待相应毫秒后醒来
      2. wait(long)和wait()还可以被notify唤醒,wait()如果不唤醒就一直等下去
      3. 他们都可以被打断唤醒
    3. 锁特性不同(重点)
      1. wait方法的调用必须先获取wait对象的锁,而sleep则无限制
      2. wait方法执行后会释放对象锁,允许其他线程获得该对象锁(我放弃cpu,但你们还可以用)
      3. 而sleep如果在synchronized代码块中执行,并不会释放对象锁(我放弃cpu,你们也用不了)

如何停止一个正在运行的线程

有三种方式可以停止线程:

  1. 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止
  2. 使用stop方法强行终止(不推荐,方法已作废)
  3. 使用interrupt方法中断线程
    1. 打断阻塞的线程(sleep,wait,join)的线程,线程会抛出InterruptedException异常
    2. 打断正常的线程,可以根据打断标记来标记是否退出线程

synchronized关键字的底层原理

synchronized【对象锁】采用互斥的方式让同一时刻至多只有一个线程能持有【对象锁】,其他线程再想获取这个【对象锁】时就会阻塞住

Monitor

Monitor被翻译为监视器,是由jvm提供,c++语言实现
在这里插入图片描述

  1. Owner:存储当前获取锁的线程的,只有一个线程可以获取
  2. EntryList:关联没有抢到锁的线程,处于Blocked状态的线程
  3. WaitSet:关联调用了wait方法的线程,处于Waiting状态的线程

Monitor实现的锁属于重量级锁,你了解过锁升级吗

  1. Monitor实现的锁属于重量级锁,里面涉及到了用户态和内核态的切换,进程的上下文切换,成本较高,性能比较低
  2. 在JDK1.6引入了两种新型锁机制:偏向锁和轻量级锁,他们的引入是为了解决在没有多线程竞争或基本没有竞争的场景下使用传统锁机制带来的性能开销问题

对象的内存结构

在HotSpot虚拟机中,对象在内存中存储的布局可分为三块区域:对象头(Header),实例数据(Instance Data)和对齐填充
在这里插入图片描述

MarkWord

在这里插入图片描述

  1. hashcode:25位的对象表示Hahs码
  2. age:对象分代年龄占4位
  3. biased_lock:偏向锁标识,占1位,0表示没有开始偏向锁,1表示开启了偏向锁
  4. thread:持有偏向锁的线程ID,占23位
  5. epoch:偏向时间戳,占2位
  6. ptr_to_lock_record:轻量级锁状态下,指向栈中锁记录的指针,占30位
  7. prt_to_heavtweight_monitor:重量级锁状态下,指向对象Monitor的指针,占30位

重量级锁的对象是怎么关联上Monitor的呢

每个Java对象都可以关联一个Monitor对象,如果使用synchronized给对象上锁(重量级)之后,该对象的MarkWord中就被设置指向Monitor对象的指针

轻量级锁

在很多的情况下,在Java程序运行时,同步块中的代码都是不存在竞争的,不同的线程交替的执行同步块中的代码。这种情况下,用重量级锁hi没必要的。因此JVM引入了轻量级锁的概念
加锁流程:
1. 在线程栈中创建一个Lock Record,将其obj字段指向锁对象
2. 通过CAS指令将Lock Record的地址存储在对象头的mark word中,如果对象处于无锁状态则修改成功,代表该线程获得了轻量级锁
3. 如果是当前线程已经持有该锁了,代表这是一次锁重入。设置Lock Record第一部分为null,起到了一个重入计数器的作用
4. 如果CAS修改失败,说明发生了竞争,需要膨胀为重量级锁
解锁过程:
1. 遍历线程栈,找到所有obj字段等于当前锁对象的Lock Record
2. 如果Lock Record的Markword为null,代表这是一次重入,将obj设置为null后continue
3. 如果Lock Record的MarkWord不为null,则利用CAS指令将对象头的markword恢复成无锁状态。如果失败则膨胀为重量级锁。

偏向锁

轻量级锁在没有竞争的时候,每次重入仍然需要执行CAS操作
引入偏向锁来做进一步优化:只有第一次使用CAS将线程ID设置到对象的MarkWord头,之后发现这个线程ID是自己的就表示没有竞争,不用重新CAS,以后只要不发生竞争,这个对象就归该线程所有。
在这里插入图片描述

JMM

  1. JMM(Java Memory Model)Java内存模型,定义了共享内存中多线程程序读写操作的行为规范,通过这些规则来规范对内存读写操作从而保证指令的正确性
  2. JMM把内存分为两块,一块是私有线程的工作区域(工作内存),一块是所有线程的共享区域(主内存)
  3. 线程跟线程之间是相互隔离,线程跟线程之间的交互需要通过主内存

在这里插入图片描述

CAS

CAS的全称是:Compare And Swap(比较再交换),他体现的是一种乐观锁的思想,在无锁情况下保证线程操作共享数据的原子性
在JUC(java.util.concurrent)包下实现的很多类都用到了CAS操作

  1. AbstractQueuedSynchornizer(AQS框架)
  2. AtomicXXX类

CAS数据交换流程

在这里插入图片描述
一个当前内存值V,旧的预期值A,即将更新的值B,当且仅当旧的预期值A和内存值V相同时,将内存值修改为B并返回true,否则什么都不做,并返回false。如果CAS操作失败,通过自选的方式等待并再次尝试,直到成功。
在这里插入图片描述

  1. 因为没有加锁,所以线程不会陷入阻塞,效率较高
  2. 如果竞争激烈,重试频繁发生,效率会受影响

CAS底层实现

CAS底层依赖一个Unsafe类来直接调用操作系统底层的CAS指令

乐观锁和悲观锁

  1. CAS 是基于乐观锁的思想:最乐观的估计,不怕别的线程来修改共享变量,就算失败了也没关系
  2. synchronized是基于悲观锁的思想:最悲观的估计,得放着其他线程来修改共享变量,我上了锁你们都别想改,我改完了解开锁,你们才有机会。

volatile

一旦一个共享变量(类的成员变量,类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:

  1. 保证线程间的可见性
  2. 禁止进行指令重排序

保证线程间的可见性

用volatile修饰共享变量,能够防止编译器等优化发生,让一个线程对共享变量的修改对另一个线程可见。

禁止进行指令重排序

用volatile修饰共享变量会在读,写共享变量时加入不同的屏障,阻止其他读写操作越过屏障,从而达到阻止指令重排序的效果。
在这里插入图片描述
volatile使用技巧

  1. 写变量让volatile修饰的变量在代码的最后位置
  2. 读变量让volatile修饰的变量在代码的最开始位置

什么是AQS

全称是AbstractQueuedSynchronizer,即抽象队列同步器。他是构建锁或者其他同步组件的基础框架

AQS和synchronized的区别

synchronizedAQS
关键字,C++实现java语言实现
悲观锁,自动释放锁悲观锁,手动开启和关闭
锁竞争激烈都是重量级锁,性能差锁竞争激烈的情况下,提供了多种解决方案

AQS的常见类

  1. ReentrantLock:阻塞式锁
  2. Semaphore:信号量
  3. CountDownLatch:倒计时锁

AQS-基本工作机制

在这里插入图片描述

AQS多个线程共同争抢资源是如何保证原子性的

使用CAS设置state状态,保证操作的原子性

AQS是公平锁还是非公平锁

  1. 新的线程与队列中的线程共同来抢资源,是非公平锁
  2. 新的线程到队列中等待,只让队列中的head线程获得锁,是公平锁

ReentrantLock

ReentrantLock翻译过来是可重入锁,相对于synchronized他具备以下特点:

  1. 可中断
  2. 可以设置超时时间
  3. 可以设置公平锁
  4. 支持多个条件变量
  5. 与synchronized一样,都支持重入

实现原理

ReentrantLock主要利用CAS+AQS队列来实现。它支持公平锁和非公平锁,两者的实现类似
构造方法接受一个可选的公平参数(默认非公平锁),当设置为true时,表示公平锁,否则为非公平锁。公平锁的效率往往没有非公平锁高,在许多线程访问的情况下,公平锁表现出较低的吞吐量。
在这里插入图片描述

  1. 线程来抢锁后使用cas的方式修改state状态,修改状态成功为1,则让exclusiveOwnerThread属性指向当前线程,获取锁成功
  2. 假如修改状态失败,则会进入双向队列中等待,head指向双向队列头部,tail只想双向队列尾部
  3. 当exclusiveOwnerThread为null的时候,则会唤醒在双向队列中等待的线程
  4. 公平锁则体现在按照先后顺序获取锁,非公平体现在不在排队的线程也可以抢锁

synchronized和Lock有什么区别

  1. 语法层面
    1. synchronized是关键字,源码在jvm中,用c++实现
    2. Lock是接口,源码由jdk提供,用java语言实现
    3. 使用synchronized时,退出同步代码块锁会自动释放,而使用lock时,需要手动调用unlock方法释放锁
  2. 功能层面
    1. 两者均属于悲观锁,都具备基本的互斥,同步,锁重入功能
    2. Lock提供了许多synchronized不具备的功能,例如公平锁,可打断,可超时,多条件变量
    3. Lock有适合不同场景的实现,如ReentrantLock,ReentrantReadWriteLock(读写锁)
  3. 性能层面
    1. 在没有竞争时,synchronized做了很多优化,如偏向锁,轻量级锁,性能不赖
    2. 在竞争激烈时,Lock的实现通常会提供更好的性能

死锁产生的条件

死锁:一个线程需要同时获取多把锁,这时就容易发生死锁
线程t1持有A的锁等待获取B锁,线程t2持有B的锁等待获取A的锁

如何进行死锁诊断

当程序出现了死锁现象,我们可以使用jdk自带的工具:jps和jstack

  1. jps:输出JVM中运行的进程状态信息
  2. stack:查看java进程内线程的堆栈信息

其他解决工具

  1. jconsole:用于对jvm的内存,线程,类的监控,是一个基于jmx的GUI性能监控工具
  2. VisualVM:故障处理工具,能够监控线程,内存情况,查看方法的CPU时间和内存中的对象,已被GC的对象,反向查看分配的堆栈。

ConcurrentHashMap

ConcurrentHashMap是一种线程安全的高效Map集合,使用数组+链表/红黑二叉树实现
采用CAS+synchronized来保证并发安全进行实现

  1. CAS控制数组节点的添加
  2. synchronized只锁定当前链表或红黑二叉树的首节点,只要hash不冲突,就不会产生并发的问题,效率得到提升

导致并发程序出现问题的根本原因是什么

java并发编程中有三大特征

  1. 原子性:一个线程在CPU中操作不可暂停,也不可中断,要不执行完成,要不不执行
  2. 可见性:
  3. 有序性

内存可见性:让一个线程对共享变量的修改对另一个线程可见
有序性:指令重排:处理器为了提高程序运行效率,可能会对输入代码进行优化,他不保证程序中各个语句的执行先后顺序同代码中的顺序一致,但是他会保证程序最终执行结果和代码顺序的结果是一致的。

线程池的核心参数

public ThreadPoolExecutor(int corePoolSize,
						 int maximumPoolSize,
						 long keepAliveTime,
						 TimeUnit unit,
						 BlockingQueue<Runnable> workQueue,
						 ThreadFactory threadFactory,
						 RejectedExecutionHandler handler)
  1. corePoolSize:核心线程数目
  2. maximumPoolSize:最大线程数目 = (核心线程 + 救急线程的最大数目)
  3. keepAliveTime生存时间-救急线程的生存时间,生存时间内没有新任务,此线程资源会释放
  4. unit:时间单位-救急线程的生存时间单位,如秒,毫秒等
  5. workQueue:当没有空闲和核心线程时,新的任务会加入到此队列排队,队列满会创建救急线程执行任务
  6. threadFactory:线程工厂-可以定制线程对象的创建,例如设置线程名字,是否是守护线程等

线程池的执行原理

在这里插入图片描述

线程池中有哪些常见的阻塞队列

workQueue-当没有空闲核心线程时,新来任务会假如到此队列排队,队列满会创建救急线程执行任务

  1. ArrayBlockingQueue:基于数组结构的有界阻塞队列,FIFO
  2. LinkedBlockingQueue:基于链表结构的有界阻塞队列,FIFO
  3. DelayedWrokQueue:是一个优先级队列,他可以保证每次出队的任务是当前队列中执行时间最靠前的
  4. SynchronousQueue:不存储元素的阻塞队列,每个插入操作都必须等待一个移除操作
ArrayBlockingQueueLinkedBlockingQueue
默认无界,支持有界强制有界
底层是链表底层是数组
是懒惰的,创建节点的时候自动添加数据提前初始化Node数组
入队会生成新的NodeNode需要是提前创建好的
两把锁(头尾)一把锁

如何确定核心线程数

  1. IO密集型任务:一般来说:文件读写,DB读写,网络请求等=》核心线程数大小设置为2N+1
  2. CPU密集型任务:一般来说:计算型代码,Bitmap转换,Gson转换等:核心线程数大小设置为N+1

线程池的种类有哪些

在java.util.concurrent.Executors类中提供了大量创建连接池的静态方法,常见就有四种

  1. 创建使用固定线程数的线程池
    在这里插入图片描述
    1. 核心线程数与最大线程数一样,没有救急线程
    2. 阻塞队列是LinkedBlockingQueue,最大容量为Integer.MAX_VALUE
      适用于任务量已知,相对耗时的任务
  2. 单线程化的线程池,他只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO)执行
    在这里插入图片描述
    1. 核心线程数和最大线程数都是1
    2. 阻塞队列是LinkedBlockingQueue,最大容量为Integer.MAX_VALUE
      适用于按照顺序执行的任务
  3. 可缓存的线程池
    在这里插入图片描述
    1. 核心线程数为0
    2. 最大线程数为Integer.MAX_VALUE
    3. 阻塞队列为SynchronousQueue:不存储元素的阻塞队列,每个插入操作都必须等待一个移除操作
      适合任务数比较密集,但每个任务执行时间较短的情况
  4. 提供了延迟和周期执行功能的ThreadPoolExectutor在这里插入图片描述

线程池的使用场景

CountDownLatch

CountDownLatch(闭锁/倒计时锁)用来进行线程同步协作,等待所有线程完成倒计时(一个或多个线程,等待其他多个线程完成某件事情后才能执行)

  1. 其中构造参数用来初始化等待计数值
  2. await()用来等待技术归零
  3. countDown()用来让计数减一

多线程使用场景(es数据批量导入)

在项目上线之前需要将数据库的数据批量导入到es索引库中,数据量高达一千万,一次性读取数据肯定会导致OOM,于是可以使用线程池方式导入,利用countDownLatch来控制,避免一次性加载太多,防止内存溢出

如何控制某个方法允许并发访问线程的数量

Semaphore信号量,是JUC包下的一个工具类,底层是AQS,我们可以通过其限制执行的线程数量
使用场景:通常用于那些资源有明确访问数量限制的场景,常用于限流

Semaphore使用步骤

  1. 创建Semaphore对象,可以给一个容量
  2. semaphore。acquire():请求一个信号量,这时候的信号量个数-1(一旦没有可使用的信号量,也即信号量个数变为负数时,再次请求的时候就会阻塞,知道其他线程释放了信号量)
  3. semaphore.release():释放一个信号量,此时信号量个数+1

对ThreadLocal的理解

ThreadLocal是多线程中对于解决线程安全的一个操作类,他会为诶个线程都分配一个独立的线程副本从而解决了变量并发访问冲突的问题。ThreadLocal同时实现了线程内的资源共享

ThreadLocal的基本使用

  1. set(value)设置值
  2. get():获取值
  3. remove()清除值

ThreadLocal的实现原理&源码解析

ThreadLocal本质来说就是一个线程内部存储类,从而让多个线程只操作自己内部的值,从而实现线程数据隔离

ThreadLocal内存泄漏问题

Java对象中的四种引用类型:强引用,软引用,弱引用,虚引用

  1. 强引用:最为普通的引用方式,表示一个对象处于有用且必须得状态,如果一个对象具有强引用,则GC并不会回收它。即是堆内存不足了,宁可出现OOM,也不会对其进行回收。
  2. 弱引用:表示一个对象处于可能有用且必须得状态。在GC线程扫描内存区域时,一旦发现弱引用,就会回收到弱引用相关联的对象。对于弱引用的回收,无关内存区域是否足够,一旦发现则会被回收。
    每一个Thread维护一个ThreadLocalMap,在ThreadLocalMap中的Entry对象继承了WeakReference。其中key为使用弱引用的ThreadLocal实例,value为线程变量的副本
    防止内存泄漏:必须remove

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1709846.html

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

相关文章

鲲鹏迁移——DevKit

参考文档 鲲鹏DevKit开发套件下载-鲲鹏社区鲲鹏社区是面向鲲鹏合作伙伴、开发者的全产业社区&#xff0c;集学习、实验、认证等功能为一体&#xff0c;是鲲鹏计算产业的官方社区。https://www.hikunpeng.com/developer/devkit/download 鲲鹏社区-官网丨凝心聚力 共创行业新价…

记录一次开源 MaxKey 安装部署

官方文档&#xff1a;https://www.maxkey.top/doc/docs/intro/ 开源代码&#xff1a;https://toscode.mulanos.cn/dromara/MaxKey 发行版&#xff1a;https://toscode.mulanos.cn/dromara/MaxKey/releases 一、准备工作 yum install -y yum-utils yum-config-manager --add-r…

CSS 之 自定义属性(变量)

一、简介 ​ CSS的自定义属性&#xff0c;又称为CSS变量或级联变量&#xff0c;用于定义一个带有值的、可重复使用的CSS属性&#xff08;变量&#xff09;。其包含的值可以在其作用域内的任意属性上重复使用&#xff0c;在使用时需要借助var()函数获取自定义属性的值。当自定义…

text-embedding 嵌入模型

为什么使用embedding 计算机只能处理数字&#xff0c;但我们希望它能够理解文字、图片或其他形式的数据。这就是embedding的作用。它将这些复杂的数据转换成数字表示&#xff0c;就像给它们贴上了标签一样。这些数字表示不仅保留了原始数据的重要信息&#xff0c;还能在计算机…

短视频商城全套源码:开启电商新纪元

随着数字媒体的快速发展&#xff0c;短视频平台已经成为人们获取信息、娱乐和社交的重要渠道。在这样一个大背景下&#xff0c;短视频商城的兴起&#xff0c;无疑为电商行业带来了新的机遇和挑战。本文将探讨短视频商城全套源码的重要性&#xff0c;以及它如何助力商家和开发者…

Vulnhub - AI-WEB-1.0靶机教程

目录 站点信息收集 c段扫描 端口扫描 目录扫描 漏洞利用 使用 burp 抓包 查询数据库名 查询数据库下的表 查询表中的字段名 查询字段中的数据 --os-shell 上传一句话木马 下载地址&#xff1a;https://download.vulnhub.com/aiweb/AI-Web-1.0.7z 我们从站点信息收…

2024年区块链,物联网与信息技术国际会议(ICBITIT 2024)

2024年区块链&#xff0c;物联网与信息技术国际会议&#xff08;ICBITIT 2024&#xff09; 2024 International Conference on Blockchain, Internet of Things, and Information Technology 会议简介&#xff1a; 2024年区块链&#xff0c;物联网与信息技术国际会议&#xff…

【调试笔记-20240528-Linux-用 OpenWrt-23.05 SDK 编译 frp 软件包】

调试笔记-系列文章目录 调试笔记-20240528-Linux-用 OpenWrt-23.05 SDK 编译 frp 软件包 文章目录 调试笔记-系列文章目录调试笔记-20240528-Linux-用 OpenWrt-23.05 SDK 编译 frp 软件包 前言一、调试环境操作系统&#xff1a;Ubuntu 22.04.4 LTS编译环境调试目标 二、调试步…

java函数编程-黑马学习笔记

第一章 01合格的函数 函数就是一个规则 合格的函数就是只要你输入相同&#xff0c;无论多少次调用&#xff0c;不论什么时间调用&#xff0c;输出是相同的。 函数可以引用外部的数据&#xff0c;但是需要去保证外部的数据不可变 static关键字修饰的静态方法本质上和函数没…

TCP 与 UDP

0. tcp 与 udp 的 异同特性 TCPUDPname传输控制协议用户数据报协议面向连接&#xff1f; 需要 传输数据前建立连接传输完毕后断开连接不需要可靠的传输数据&#xff1f; 可靠 有确认机制&#xff08;三次握手&#xff09; 有确认、窗口、重传、拥塞控制的机制保证数据可靠传输…

10Django项目--用户管理系统--改

对应视频链接点击直达 10Django项目--用户管理系统--改 对应视频链接点击直达改a&#xff0c;本质b&#xff0c;修改(更新) 页面相关a&#xff0c;index页面新增操作按钮b&#xff0c;修改(更新)页面c&#xff0c;路由和函数 OVER&#xff0c;不会有人不会吧不会的加Q139400651…

项目9-网页聊天室3(主界面之用户信息)

1.前端页面 CSS: 如何让img里的图片自适应div&#xff0c;且不变形_img自适应div大小 铺满且不变形-CSDN博客 JavaScript/jQuery 如何改变一个img元素的src属性|极客教程 (geek-docs.com) 2.要求 左上角显示用户的昵称和头像. 3.后端代码 3.1 添加拦截器 3.2 注册拦截器 …

深入解析MySQL 8中的角色与用户管理

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 &#x1f38f;&#xff1a;你只管努力&#xff0c;剩下的交给时间 &#x1f3e0; &#xff1a;小破站 深入解析MySQL 8中的角色与用户管理 前言角色和用户的基础概念用户&#xff08;User&#xff09;…

收银系统源码--零售连锁店铺如何选择适合自己的收银系统?

如果你现在还认为小便利店只要简单的收款&#xff0c;只有大型的连锁便利店才需要收银软件和管理软件&#xff0c;那你就错了&#xff0c;连锁品牌的便利店是必须要用到专业的收银软件&#xff0c;但是小微型的便利店更应该要用专门的软件&#xff0c; 在各行各业逐步革新互联网…

【ai】LiveKit Agent 的example及python本地开发模式工程实例

title: ‘LiveKit Agent Playground’ playgroundLiveKit Community playground的环境变量&#xff1a;LiveKit API # LiveKit API Configuration LIVEKIT_API_KEYYOUR_API_KEY LIVEKIT_API_SECRETYOUR_API_SECRET# Public configuration NEXT_PUBLIC_LIVEKIT_URLwss://YOUR_…

计算机网络基础 - 计算机网络和因特网(1)

计算机网络基础 计算机网络和因特网什么是 Internet?具体构造的的角度服务角度网络结构 网络边缘网络核心电路交换分组交换概述排队时延和分组丢失转发表和路由选择协议按照有无网络层的连接 分组交换 VS 电路交换 接入网DSL 因特网接入电缆因特网接入光纤到户 FTTH无线接入网…

十五、Python模块 1、(入门一定看!!!)「长期更新Python简单入门到适用」

首先什么是模块&#xff1f; 小伙伴们经常看我写的教程不难发现&#xff0c;前面我们用过几次模块就是sys的那个&#xff0c;其实python不仅标准库中包含了大量的模块&#xff08;也被称之为准模块&#xff09;&#xff0c;还有大量的第三方模块&#xff0c;开发者也可以自己发…

图卷积神经网络的简史 及其与卷积神经网络的异同

图卷积神经网络&#xff08;GCN&#xff09;已经在处理图结构数据方面取得了巨大的成功。在本小节中&#xff0c;我们将深入探讨图卷积神经网络的起源、发展历程&#xff0c;并提供一个简单的Python代码实现示例&#xff0c;以帮助读者更好地理解这一概念。 图卷积神经网络的简…

Echarts图表库推荐以及使用Echarts实现饼图端头弧形效果

推荐Echarts图表库官方链接http://www.ppchart.com/#/ 下面是一段实现饼图端头弧形效果的Echarts代码 下面代码可以直接新建html文件运行看效果也可以看我下面贴的效果图 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8&q…

【深度学习实战—8】:基于MediaPipe的人脸检测

✨博客主页&#xff1a;王乐予&#x1f388; ✨年轻人要&#xff1a;Living for the moment&#xff08;活在当下&#xff09;&#xff01;&#x1f4aa; &#x1f3c6;推荐专栏&#xff1a;【图像处理】【千锤百炼Python】【深度学习】【排序算法】 目录 &#x1f63a;一、Med…