interview5-多线程篇

2023-10-27

一、线程的基础知识

(1)线程与进程

程序由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至 CPU,数据加载至内存。在指令运行过程中还需要用到磁盘、网络等设备。进程就是用来加载指令、管理内存、管理 IO 的。

进程:当一个程序被运行,从磁盘加载这个程序的代码至内存,这时就开启了一个进程。

一个线程就是一个指令流,将指令流中的一条条指令以一定的顺序交给 CPU 执行。

一个进程之内可以分为一到多个线程。

二者对比

  • 进程是正在运行程序的实例,进程中包含了线程,每个线程执行不同的任务

  • 不同的进程使用不同的内存空间,在当前进程下的所有线程可以共享内存空间

  • 线程更轻量,线程上下文切换成本一般上要比进程上下文切换低(上下文切换指的是从一个线程切换到另一个线程)

(2)并行与并发

并发(concurrent)是同一时间轮流应对(dealing with)多件事情的能力

并行(parallel)是同一时间同时动手做(doing)多件事情的能力

现在都是多核CPU,在多核CPU下

  • 并发是同一时间应对多件事情的能力,多个线程轮流使用一个或多个CPU

  • 并行是同一时间动手做多件事情的能力,4核CPU同时执行4个线程

(3)线程创建的方式

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

  • 继承Thread类

  • 实现runnable接口

  • 实现Callable接口

  • 线程池创建线程

(4)runnable和callable

区别:

  1. Runnable 接口run方法没有返回值

  2. Callable接口call方法有返回值,是个泛型,和Future、FutureTask配合可以用来获取异步执行的结果

  3. Callable接口的call()方法允许抛出异常;而Runnable接口的run()方法的异常只能在内部消化,不能继续上抛

(5)线程状态

JDK中的Thread类中的枚举State:

新建(NEW)、可运行(RUNNABLE)、阻塞(BLOCKED)、等待( WAITING )、时间等待(TIMED_WALTING)、终止(TERMINATED)

线程状态变化:

  1. 创建线程对象是新建状态

  2. 调用了start()方法转变为可运行状态

  3. 线程获取到了CPU的执行权,执行结束是终止状态

  4. 在可执行状态的过程中,如果没有获取CPU的执行权,可能会切换其他状态

    • 如果没有获取锁(synchronized或lock)进入阻塞状态,获得锁再切换为可执行状态

    • 如果线程调用了wait()方法进入等待状态,其他线程调用notify()唤醒后可切换为可执行状态

    • 如果线程调用了sleep(50)方法,进入计时等待状态,到时间后可切换为可执行状态

(6)wait和sleep方法的不同

wait和sleep方法都是用于让当前线程进入阻塞状态,但它们之间存在着几个主要的区别:

  1. 来源:wait方法来自Object类,而sleep方法来自Thread类。

  2. 线程状态:wait方法会释放对象的锁,使得其他线程可以进入同步方法或者同步代码块,而sleep方法在阻塞期间不会释放锁。

  3. 使用场景:wait,notify和notifyAll方法只能在同步控制方法或者同步控制块里面使用,而sleep方法可以在任何地方使用。

  4. 定时性:sleep方法可以接受一个时间参数,让线程暂停指定的时间后自动退出阻塞状态,而wait方法没有这个功能。当没有指定等待时间时,线程会一直等待,直到被其他线程中断才能结束等待。

  5. 唤醒方式:sleep方法不需要被唤醒,等待时间过后会自动退出阻塞状态。而wait方法在被其他线程中断后才能退出阻塞状态。

  6. 锁特性不同(重点):

    1. wait 方法的调用必须先获取 wait 对象的锁,而 sleep 则无此限制

    2. wait 方法执行后会释放对象锁,允许其它线程获得该对象锁(我放弃 cpu,但你们还可以用)

    3. 而 sleep 如果在 synchronized 代码块中执行,并不会释放对象锁(我放弃 cpu,你们也用不了)

总的来说,虽然这两个方法都可能导致线程进入阻塞状态,但在使用场景、线程状态、定时性和唤醒方式上都有显著的区别。

(7)如何保证线程顺序执行

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

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

(8)notify()和notifyAll()区别

notify:只随机唤醒一个 wait 线程

notifyAll:唤醒所有wait的线程

(9)线程的run()和start()区别

start(): 用来启动线程,通过该线程调用run方法执行run方法中所定义的逻辑代码。start方法只能被调用一次。

run(): 封装了要被线程执行的代码,可以被调用多次。

(10)停止线程

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

  • 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止

  • 使用stop方法强行终止(不推荐,方法已作废)

  • 使用interrupt方法中断线程

    • 打断阻塞的线程( sleep,wait,join )的线程,线程会抛出InterruptedException异常

    • 打断正常的线程,可以根据打断状态来标记是否退出线程

在Java中,Thread.stop()方法已经被废弃,因为它可能导致线程在任意点停止,这可能会引发许多问题,如数据不一致、资源泄露等。

相比之下,Thread.interrupt()方法是一种更安全的终止线程的方式。该方法设置线程的中断状态,然后让线程自行决定如何响应中断。线程可以检查中断状态,并决定如何优雅地停止自己。例如,如果线程正在执行一个循环,它可以在每次循环时检查中断状态,并在适当的时候退出循环。

使用Thread.interrupt()方法可以让线程有机会清理资源、保存状态,并以一种可预测的方式停止。

二、线程中并发安全

(1)synchronized关键字的底层原理

  • synchronized【对象锁】采用互斥的方式让同一时刻至多只有一个线程能持有【对象锁】

  • 它的底层由monitor实现的,monitor是jvm级别的对象( C++实现),线程获得锁需要使用对象(锁)关联monitor

  • 在monitor内部有三个属性,分别是owner、entrylist、waitset

  • 其中owner是关联的获得锁的线程,并且只能关联一个线程;entrylist关联的是处于阻塞状态的线程;waitset关联的是处于Waiting状态的线程

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

Java中的synchronized有偏向锁、轻量级锁、重量级锁三种形式,分别对应了锁只被一个线程持有、不同线程交替持有锁、多线程竞争锁三种情况。

描述
重量级锁 底层使用的Monitor实现,里面涉及到了用户态和内核态的切换、进程的用户态和内核态的切换、进程的上下文切换,成本较高,性能比较低。
轻量级锁 线程加锁的时间是错开的(也就是没有竞争),可以使用轻量级锁来优化。轻量级修改了对象头的锁标志,相对重量级锁性能提升很多。每次修改都是CAS操作,保证原子性。
偏向锁 一段很长的时间内都只被一个线程使用锁,可以使用了偏向锁,在第一次获得锁时,会有一个CAS操作,之后该线程再获取锁,只需要判断mark word中是否是自己的线程id即可,而不是开销相对较大的CAS命令。

一旦锁发生了竞争,都会升级为重量级锁。

(2)JMM

JMM(Java Memory Model)Java内存模型,定义了共享内存多线程程序读写操作的行为规范,通过这些规则来规范对内存的读写操作从而保证指令的正确性。

JMM把内存分为两块,一块是私有线程的工作区域(工作内存),一块是所有线程的共享区域(主内存)。

线程跟线程之间是相互隔离,线程跟线程交互需要通过主内存。

(3)CAS

CAS的全称是: Compare And Swap(比较再交换),它体现的一种乐观锁的思想,在无锁情况下保证线程操作共享数据的原子性。

在JUC( java.util.concurrent )包下实现的很多类都用到了CAS操作:

  • AbstractQueuedSynchronizer(AQS框架)

  • AtomicXXX类

在操作共享变量的时候使用的自旋锁,效率上更高一些。CAS的底层是调用的Unsafe类中的方法,都是操作系统提供的,其他语言实现。

CAS 是基于乐观锁的思想:最乐观的估计,不怕别的线程来修改共享变量,就算改了也没关系,我吃亏点再重试呗。

(4)AQS

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

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

AQS常见的实现类:

  • ReentrantLock 阻塞式锁

  • Semaphore 信号量

  • CountDownLatch 倒计时锁

AQS内部维护了一个先进先出的双向队列,队列中存储的排队的线程。

在AQS内部还有一个属性state,这个state就相当于是一个资源,默认是0(无锁状态),如果队列中的有一个线程修改成功了state为1,则当前线程就相等于获取了资源。

在对state修改的时候使用的cas操作,保证多个线程修改的情况下原子性。

(5)ReentrantLock的实现原理

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

  • 可中断

  • 可以设置超时时间

  • 可以设置公平锁

  • 支持多个条件变量

  • 与synchronized一样,都支持重入

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

(6)synchronized和Lock有什么区别

  1. 语法层面:

    • synchronized 是关键字,源码在 jvm 中,用 c++ 语言实现

    • Lock 是接口,源码由 jdk 提供,用 java 语言实现

    • 使用 synchronized 时,退出同步代码块锁会自动释放,而使用 Lock 时,需要手动调用 unlock 方法释放锁

  2. 功能层面:

    • 二者均属于悲观锁、都具备基本的互斥、同步、锁重入功能

    • Lock 提供了许多 synchronized 不具备的功能,例如公平锁、可打断、可超时、多条件变量

    • Lock 有适合不同场景的实现,如 ReentrantLock, ReentrantReadWriteLock(读写锁)

  3. 性能层面:

    • 在没有竞争时,synchronized 做了很多优化,如偏向锁、轻量级锁,性能不赖

    • 在竞争激烈时,Lock 的实现通常会提供更好的性能

(7)死锁

死锁产生的条件:一个线程需要同时获取多把锁,这时就容易发生死锁。

如何进行死锁诊断?

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

  • jps:输出JVM中运行的进程状态信息

  • jstack:查看java进程内线程的堆栈信息

  • 可视化工具jconsole、VisualVM也可以检查死锁问题

(8)volatile

一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:保证线程间的可见性、 禁止进行指令重排序

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

  2. 禁止进行指令重排序:用 volatile 修饰共享变量会在读、写共享变量时加入不同的屏障,阻止其他读写操作越过屏障,从而达到阻止重排序的效果。

(9)ConcurrentHashMap

ConcurrentHashMap 是一种线程安全的高效Map集合

底层数据结构:

  • JDK1.7底层采用分段的数组+链表实现

  • JDK1.8 采用的数据结构跟HashMap1.8的结构一样,数组+链表/红黑二叉树。

加锁的方式:

  • JDK1.7采用Segment分段锁,底层使用的是ReentrantLock

  • JDK1.8采用CAS添加新节点,采用synchronized锁定链表或红黑二叉树的首节点,相对Segment分段锁粒度更细,性能更好

(10) 导致并发程序出现问题的根本原因

Java程序中怎么保证多线程的执行安全?

Java并发编程三大特性: 原子性可见性有序性

  • 原子性:一个线程在CPU中操作不可暂停,也不可中断,要不执行完成,要不不执行

  • 内存可见性:让一个线程对共享变量的修改对另一个线程可见

  • 有序性:指令重排,处理器为了提高程序运行效率,可能会对输入代码进行优化,它不保证程序中各个语句的执行先后顺序同代码中的顺序一致,但是它会保证程序最终执行结果和代码顺序执行的结果是一致的

三、线程池

(1)线程池的核心参数

  1. corePoolSize 核心线程数目

  2. maximumPoolSize 最大线程数目 = (核心线程+救急线程的最大数目)

  3. keepAliveTime 生存时间 - 救急线程的生存时间,生存时间内没有新任务,此线程资源会释放

  4. unit 时间单位 - 救急线程的生存时间单位,如秒、毫秒等

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

  6. threadFactory 线程工厂 - 可以定制线程对象的创建,例如设置线程名字、是否是守护线程等

  7. handler 拒绝策略 - 当所有线程都在繁忙,workQueue 也放满时,会触发拒绝策略

线程池的执行原理:

拒绝策略:

  1. AbortPolicy:直接抛出异常,默认策略;

  2. CallerRunsPolicy:用调用者所在的线程来执行任务;

  3. DiscardOldestPolicy:丢弃阻塞队列中靠最前的任务,并执行当前任务;

  4. DiscardPolicy:直接丢弃任务;

(2)线程池中常见的阻塞队列

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

  1. ArrayBlockingQueue:基于数组结构的有界阻塞队列,FIFO

  2. LinkedBlockingQueue:基于链表结构的有界阻塞队列,FIFO

  3. DelayedWorkQueue :是一个优先级队列,它可以保证每次出队的任务都是当前队列中执行时间最靠前的。

  4. SynchronousQueue:不存储元素的阻塞队列,每个插入操作都必须等待一个移出操作。

LinkedBlockingQueue ArrayBlockingQueue
默认无界,支持有界 强制有界
底层是链表 底层是数组
是懒惰的,创建节点的时候添加数据 提前初始化 Node 数组
入队会生成新 Node Node需要是提前创建好的
两把锁(头尾) 一把锁

(3)如何确定核心线程数

IO密集型任务一般来说:文件读写、DB读写、网络请求等。核心线程数大小设置为2N+1

CPU密集型任务一般来说:计算型代码、Bitmap转换、Gson转换等。核心线程数大小设置为N+1

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#aa5500">// 查看机器的CPU核数</span>
<span style="color:#000000">System</span>.<span style="color:#000000">out</span>.<span style="color:#000000">println</span>(<span style="color:#000000">Runtime</span>.<span style="color:#000000">getRuntime</span>().<span style="color:#000000">availableProcessors</span>());</span></span>

并发高、业务执行时间长,解决这种类型任务的关键不在于线程池而在于整体架构的设计,看看这些业务里面某些数据是否能做缓存是第一步,增加服务器是第二步,至于线程池的设置。

(4)线程池的种类有哪些

1. newFixedThreadPool:创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待

2. newSingleThreadExecutor:创建一个单线程化的线程池,它只会用唯一的工作线程来执行任 务,保证所有任务按照指定顺序(FIFO)执行

3. newCachedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程

4. newScheduledThreadPool:可以执行延迟任务的线程池,支持定时及周期性任务执行

为什么不建议用Executors创建线程池?

Executors是Java中创建线程池的一种常见方式,但不建议使用它的主要原因有以下几点:

  1. 资源耗尽风险:Executors创建的线程池没有任何的限制,如果任务提交的速度远快于任务 执行的速度,那么线程池中的线程数量会不断增加,直到耗尽系统资源。

  2. 线程管理问题:Executors创建的线程池没有提供任何的管理机制,例如线程的生命周期管理、线程的最大并发数设置、任务队列的管理等,这样可能会导致程序的行为不可预测。

  3. 关闭线程池困难:Executors创建的线程池没有提供关闭线程池的方法,如果你要停止线程池的运行,只能调用shutdown()或shutdownNow()方法,但这样的操作可能会引发一些未预期的行为。

  4. 不利于性能调优:由于Executors创建的线程池没有提供任何参数来设置线程池的行为,因此不利于根据实际需要进行性能调优。

因此,虽然Executors提供了一种简单的方式来创建线程池,但在实际的生产环境中,我们更推荐使用ThreadPoolExecutor来创建线程池,因为它提供了更多的控制和灵活性。

(5)线程池使用场景

批量导入:使用了线程池+CountDownLatch批量把数据库中的数据导入到了ES(任意)中,避免OOM。

数据汇总:调用多个接口来汇总数据,如果所有接口(或部分接口)的没有依赖关系,就可以使用线程池+future来提升性能。

异步线程(线程池):为了避免下一级方法影响上一级方法(性能考虑),可使用异步线程调用下一个方法(不需要下一级方法返回值),可以提升方法响应时间。

(6)ThreadLocal

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

ThreadLocal 主要功能有两个:

  • 第一个是可以实现资源对象的线程隔离,让每个线程各用各的资源对象,避免争用引发的线程安全问题。

  • 第二个是实现了线程内的资源共享。

每个线程内有一个 ThreadLocalMap 类型的成员变量,用来存储资源对象 ,原理:

  1. 调用 set 方法,就是以 ThreadLocal 自己作为 key,资源对象作为 value,放入当前线程的 ThreadLocalMap 集合中

  2. 调用 get 方法,就是以 ThreadLocal 自己作为 key,到当前线程中查找关联的资源值

  3. 调用 remove 方法,就是以 ThreadLocal 自己作为 key,移除当前线程关联的资源值

ThreadLocal内存泄漏问题:ThreadLocalMap 中的 key 是弱引用,值为强引用; key 会被GC 释放内存,关联 value 的内存并不会释放。建议主动 remove 释放 key,value。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

interview5-多线程篇 的相关文章

  • muduo1——编程风格:面向对象的编程和基于对象的编程(上)

    muduo库其实不是面向对象的编程 而是基于对象的编程 那么在进入正式的muduo源码分析之前 先来看看这两种编程风格 一 面向对象编程风格 通过对一个线程类的封装来进行讲解 Thread是一个抽象类不能实例化对象 TestThread是派
  • wxWidgets开发之多线程wxThread编程

    上节说到使用wxCondition来实现某一消息处理的业务场景的多线程处理方法 在此之前先分享一下wxCondition用法 条件变量 最常用在多线程环境下 用来指示当前所在线程的某些条件已经满足 其他线程可以共享该线程的数据 或者去完成预
  • Java 并发工具包 java.util.concurrent 用户指南

    http blog csdn net defonds article details 44021605 comments 译序 本指南根据 Jakob Jenkov 最新博客翻译 请随时关注博客更新 http tutorials jenko
  • synchronized方法和代码块

    1 同步 由于多线程并发存在数据不安全问题 为了保证数据的安全性需要一些特殊的手段来维持 数据不安全主要是针对修改来说的 如果一个数据只能读不能修改几乎不会产生什么安全问题 只有修改数据的时候容易产生一些差错导致多线程并发造成数据不安全 从
  • Qt中的线程详解

    概述 在多核时代 CPU 的主频已经进入瓶 颈 另辟蹊径地提高程序运行效率就是使用线程 充分利用多核的优势 线程可以看做是 轻量级进程 线程即可以由操作系统管理 也可以由应用程序管 1 为什么要使用线程 我们都知道 进程线程的概念是非常重要
  • python中的GIL详解

    python中的GIL详解 参考Python GIL 锁简述 GIL是什么 首先需要明确的一点是GIL并不是Python的特性 它是在实现Python解析器 CPython 时所引入的一个概念 就好比C 是一套语言 语法 标准 但是可以用不
  • log4net使用

    说明 本程序演示如何利用log4net记录程序日志信息 log4net是一个功能著名的开源日志记录组件 利用log4net可以方便地将日志信息记录到文件 控制台 Windows事件日志和数据库 包括MS SQL Server Access
  • 使用org.apache.tools.zip包操作文件

    import java io import org apache tools zip import java util Enumeration 功能 zip压缩 解压 支持中文文件名 说明 本程序通过使用Apache Ant里提供的zip工
  • C++11多线程std::thread的简单使用

    文章转载自http blog csdn net star530 article details 24186783 在cocos2dx 2 0时代 我们使用的是pthread库 是一套用户级线程库 被广泛地使用在跨平台应用上 但在cocos2
  • python基于字典多线程目录枚举工具

    基于字典多线程目录枚举工具 整体思路 命令行参数获取 字典文件的读取 多线程访问 命令行参数获得 使用模块 sys getopt sys argv获取命令行执行的数据 参数获得 opt args getopt getopt sys argv
  • 【多线程】线程安全、锁的同步和异步

    一 基本概念 线程安全 当多个线程访问某一个类 对象或方法 时 这个类始终都能表现出正确的行为 那么这个类 对象或方法 就是线程安全的 非线程安全 非线程主要是指多个线程对同一个对象中的同一个实例变量进行操作时会出现值被更改 值不同步的情况
  • Java多线程:解决高并发环境下数据插入重复问题

    1 背景描述 应用框架 Spring SpringMVC Hibernate 数据库 Oracle11g 一家文学网站向我系统推多线程低并发推送数据 我这边观察日志和数据库 发现有一个作者被存储了2次到数据库中 按照程序的编写逻辑 重复的数
  • 多线程的异步调用(一)

    最近手头做的项目中 用到了多线程的异步调用 在控制线程中实时的检测硬件的变化 如果硬件发生了某些变化 那么需要通知别的模块做一些相应的操作 为了让这些操作不会影响控制线程的继续运行 就在多线程中使用了异步调用的方法 using System
  • Java多线程的同步问题

    在多线程的编程环境中 可能会有两个或者更多的线程试图同时访问一个有限的资源 必须对这种潜在的资源冲突进行预防 解决办法 在线程使用一个资源的时候 我们为其加锁即可 访问资源的第一个线程为其加上锁以后 其它线程便不能访问那个资源 除非获得那个
  • 如何终止一个无限循环线程和 程序退出时销毁线程

    http zhidao baidu com question 299079849 html android 启动了一个子线程 这个子线程是一个死循环 不成的打印 Hello 现在要实现点击一个Button 让这个子线程终止 用什么方法啊 s
  • 多线程事务的实现

    为了提高效率 在批量执行SQL时 可以采用多线程并发执行的方式 每个线程在执行完SQL后 暂时不提交事务 而是等待所有线程的SQL执行成功后 一起进行提交 如果其中任何一个线程执行失败 则所有线程都会回滚 一 springboot多线程 声
  • 01、Java并发 Java ExecutorService

    ExecutorService 是 Java java util concurrent 包的重要组成部分 是 Java JDK 提供的框架 用于简化异步模式下任务的执行 一般来说 ExecutorService 会自动提供一个线程池和相关
  • Java多线程(四):什么是死锁以及如何解决死锁

    目录 1 什么是死锁 2 死锁产生的原因 3 如何解决死锁问题 3 1 改变环路等待条件 3 2 破坏请求并持有条件 1 什么是死锁 死锁 是指两个或两个以上的进程在执行过程中 由于竞争资源或者由于彼此通信而造成的一种阻塞的现象 若无外力作
  • QT实现多线程,以及子线程调用主线程方法与变量

    实现思路 第一步需要将子线程声明为主线程的友元类 第二步是将主线程类对象的地址通过信号槽传递给子线程中创建的对象 使得子线程能访问主线程的数据的 1 子线程 displayresult h 头文件 伪代码 include tabwindow
  • Java线程(Thread)生命周期的6种状态

    当线程被创建并启动以后 它既不是一启动就进入了执行状态 也不是一直处于执行状态 在线程的生命周期中 可能处于不同的状态 java lang Thread State 列举出了这6种线程状态 线程状态 导致状态发生条件 New 新建 线程刚被

随机推荐

  • 被骗几十万总结出来的Ddos攻击防护经验!

    转载地址 http www ijiandao com safe cto 15952 html 本人从事网络安全行业20年 有15年防ddos攻击防护经验 被骗了很多回 都说能防300G 500G 买完就防不住了 本文当然重点给大家说明 dd
  • Flask4:methods=[‘POST‘, ‘GET‘]

    从服务器上获取数据 用GET请求 前端把数据发给服务器 用POST请求 在 app route上 添加methods参数 这个参数是一个列表类型 可以传递多个 右键页面 检查 中
  • Vue3/ Vue3 和 Vue2 生命周期函数不同点 总结、Vue2 和 Vue3 里面父组件的生命周期顺序

    一 Vue3 x 和 Vue2 x 生命周期函数不同点 总结 Vue2 vue3 beforeCreate gt setup 开始创建组件之前执行 created gt setup 开始创建组件之前执行 beforeMount gt onB
  • 【满分】【华为OD机试真题2023 JS】简单的解压缩算法

    华为OD机试真题 2023年度机试题库全覆盖 刷题指南点这里 简单的解压缩算法 知识点栈 时间限制 1s 空间限制 256MB 限定语言 不限 题目描述 现需要实现一种算法 能将一组压缩字符串还原成原始字符串 还原规则如下 1 字符后面加数
  • 高并发短信平台实现

    01 短信介绍 在项目介绍的时候 已经定义了austin项目的核心功能 发送消息 我认为 短信是在一整个消息推送平台里最重要的一个消息类型了 毕竟关联了很多重要的业务场景 想想我们日常使用APP时的场景 验证码 登录注册 支付等等重要场景
  • matplotlib 绘制Sigmoid函数,Tanh函数,ReLU函数

    import numpy as np import matplotlib pyplot as plt def sigmoid x return 1 1 np exp x def tanh x return np exp x np exp x
  • python global函数用法及常用的 global函数代码

    Python中的 global函数是用于在程序中定义变量的函数 在我们实际的开发中 我们可能会用到 global函数来定义变量 但是我们在这里就不具体介绍它的用法了 global函数定义变量的方法 global函数使用参数a来指定变量在程序
  • 外卖点餐系统小程序 PHP+UniAPP

    一 介绍 本项目是给某大学餐厅开发的外面点餐系统 该项目针对校内的学生 配送由学校的学生负责配送 因此 该项目不同于互联网的外卖点餐系统 该系统支持属于 Saas 系统 由平台端 商家端 用户端 以及配送端组成 其中 平台端 商家端是由基于
  • 520七夕表白,还不懂浪漫?4套代码教会你如何深情表白【建议收藏】❤️

    马上又到了脱单的黄金时刻 七夕啦 如果你有喜欢的女孩子 一定要趁着这个时候把喜欢说出口 但是该不会还有人表白在学校的操场上摆着爱心蜡烛抱一束花喊一堆人来围观吧 No 请你立刻马上放弃这个计划 毫无心意不说 对于女孩子来说是真的很社死啊 PS
  • linux 查看java安装目录

    这本阿里P8撰写的算法笔记 再次推荐给大家 身边不少朋友学完这本书最后加入大厂 Github 疯传 史上最强悍 阿里大佬 LeetCode刷题手册 开放下载了 获取java安装路径前要判断是否已经安装成功java 执行命令 java 1 U
  • 清晰图解,一图看懂图卷积GCN、时空图卷积ST-GCN

    目录 1 前言 2 普通卷积与图卷积 2 1 普通卷积 2 2 图卷积 3 ST GCN图卷积的代码解读 4 图卷积的缺陷 5 参考文献 6 联系方式 1 前言 本文为我阅读论文 Spatial Temporal Graph Convolu
  • 微信小程序API~GET

    框架提供丰富的微信原生API 可以方便的调起微信提供的能力 如获取用户信息 本地存储 支付功能等 1 wx on 开头的 API 是监听某个事件发生的API接口 接受一个 CALLBACK 函数作为参数 当该事件触发时 会调用 CALLBA
  • libmysqlclient.so.15: cannot open shared object file: No such file or directory

    libmysqlclient so 15 cannot open shared object file No such file or directory 分类 mysql服务器管理优化 2009 06 02 16 11 26769人阅读
  • DC系列漏洞靶场-渗透测试学习复现(DC-6)

    DC 6是一个易受攻击的实验环境 最终目的是让攻击者获得root权限 并读取flag DC 6使用的操作系统为Debian 64位 靶场下载链接 1 http www five86 com downloads DC 6 zip 2 http
  • P2141 [NOIP2014 普及组] 珠心算测验

    题目描述 珠心算是一种通过在脑中模拟算盘变化来完成快速运算的一种计算技术 珠心算训练 既能够开发智力 又能够为日常生活带来很多便利 因而在很多学校得到普及 某学校的珠心算老师采用一种快速考察珠心算加法能力的测验方法 他随机生成一个正整数集合
  • HTML之表格篇——表格的嵌套

    表格的嵌套一方面是为使页面 贴子 的外观更为漂亮 利用表格嵌套来编辑出复杂而精美的效果 另一方面是出于布局需要 用一些嵌套方式的表格来做精确的编排 或者二者兼而有之 熟练地掌握表格的嵌套技巧并不是很困难的 只要你思路清晰 对表格的整体嵌套构
  • Shiro源码分析之ShiroFilterFactoryBean

    创建核心Filter 同其他框架一样 都有个切入点 这个核心Filter就是拦截所有请求的 通过web xml中配置的Filer进入 执行init方法获取这个instance 调用下面的createInstance方法创建核心Filter
  • 学习《TensorFlow实战Google深度学习框架》(九)LeNet-5模型

    文章目录 6 4 经典卷积网络模型 6 4 4 LeNet 5模型 LeNet 5模型的架构 源代码 6 4 经典卷积网络模型 6 4 4 LeNet 5模型 LeNet 5模型是Yann LeCun教授于1998年在论文Gradient
  • hash函数(哈希表)

    一 什么叫做散列表 哈希表 散列表是存储key value映射的一种集合 散列表也叫做哈希表 散列表底层也是数组 只是通过一种hash函数来计算他的key值 二 hash函数 在Java中每一个对象都有属于自己的hashcode 这个has
  • interview5-多线程篇

    一 线程的基础知识 1 线程与进程 程序由指令和数据组成 但这些指令要运行 数据要读写 就必须将指令加载至 CPU 数据加载至内存 在指令运行过程中还需要用到磁盘 网络等设备 进程就是用来加载指令 管理内存 管理 IO 的 进程 当一个程序