【高频面试题】多线程篇

文章目录

  • 一、线程的基础知识
    • 1.线程与进程的区别
    • 2.并行和并发有什么区别?
    • 3.创建线程的方式有哪些?
      • 3.1.Runnable 和 Callable 有什么区别?
      • 3.2.run()和 start()有什么区别?
    • 4.线程包括哪些状态,状态之间是如何变化的
      • 4.1.线程包括哪些状态?
      • 4.2.状态之间是如何变化的?
    • 5.新建 T1、T2、T3 三个线程,如何保证它们按顺序执行?
    • 6.notify()和 notifyAll()有什么区别?
    • 7.java中wait和sleep方法的不同?
    • 8.如何停止一个正在运行的线程?
  • 2.线程中并发安全
    • 9.synchronized关键字的底层原理
    • 10.谈谈 JMM(Java内存模型)
    • 11.什么是CAS?
    • 12.请谈谈你对 volatile 的理解
      • 12.1.保证线程间的可见性
      • 12.1.禁止进行指令重排序
    • 13.什么是AQS?
    • 14.ReentrantLock的实现原理
    • 15.synchronized和Lock有什么区别 ?
    • 16.死锁产生的条件是什么?
    • 17.聊一下ConcurrentHashMap
    • 18.导致并发程序出现问题的根本原因是什么
  • 3.线程池
    • 19.说一下线程池的核心参数(线程池的执行原理知道嘛)
    • 20.线程池中有哪些常见的阻塞队列
    • 21.如何确定核心线程数
    • 22.线程池的种类有哪些
    • 23.为什么不建议用Executors创建线程池

一、线程的基础知识

1.线程与进程的区别

程序由指令数据组成,这些指令要运行,数据要读写,就必须将指令加载至 CPU数据加载至内存

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

二者对比

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

2.并行和并发有什么区别?

在这里插入图片描述

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

  1. 并发同一时间应对多件事情的能力多个线程轮流使用一个或多个CPU
  2. 并行是同一时间动手做多件事情的能力,4核CPU同时执行4个线程

3.创建线程的方式有哪些?

  1. 继承Thread类
    在这里插入图片描述

  2. 实现runnable接口
    在这里插入图片描述

  3. 实现Callable接口
    在这里插入图片描述

  4. 线程池创建线程(项目常用)
    在这里插入图片描述


3.1.Runnable 和 Callable 有什么区别?

参考回答:

  • Runnable 接口run方法没有返回值
  • Callable接口call方法有返回值,是个泛型,和Future、FutureTask配合可以用来获取异步执行的结果
  • Callable接口的call()方法允许抛出异常;而Runnable接口的run()方法的异常只能在内部消化(try catch),不能继续上抛
    **加粗样式**

3.2.run()和 start()有什么区别?

  • 方法性质不同:run 是一个普通方法,而 start 是开启新线程的方法
  • 执行速度不同:调用 run 方法立即执行任务,调用 start 方法是将线程的状态改为就绪状态,不会立即执行。(调用start()方法的时候线程不是立即执行,而是进入到一个等待状态,等待CPU进行调度)
  • 调用次数不同:run 方法可以被重复调用,而 start 方法只能被调用一次。
  • start 方法之所以不能被重复调用的原因是,线程的状态是不可逆的,Thread 在 start的实现源码中做了判断,如果线程不是新建状态 NEW,则会抛出非法线程状态异常 IllegalThreadStateException。 ​

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

4.1.线程包括哪些状态?

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

4.2.状态之间是如何变化的?

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

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

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

t.join()
阻塞调用此方法的线程进入timed_waiting
直到线程t执行完成后此线程再继续执行
在这里插入图片描述


6.notify()和 notifyAll()有什么区别?

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


7.java中wait和sleep方法的不同?

共同点
wait() ,wait(long) 和 sleep(long) 的效果都是让当前线程暂时放弃 CPU 的使用权进入阻塞状态
不同点
不同点

  1. 方法归属不同

sleep(long) 是 Thread 的静态方法
而 wait(),wait(long) 都是 Object 的成员方法每个对象都有

  1. 醒来时机不同

执行 sleep(long) 和 wait(long) 的线程都会在等待相应毫秒后醒来
wait(long) 和 wait() 还可以被 notify 唤醒,wait() 如果不唤醒一直等下去
它们都可以被打断唤醒

  1. 锁特性不同(重点)

wait 方法的调用必须先获取 wait 对象的锁,而 sleep 则无此限制
wait 方法执行后会释放对象锁,允许其它线程获得该对象锁(我放弃 cpu,但你们还可以用)

也就是只要执行到wait()方法不管wait方法有没有执行完都会立即释放锁,别的线程就可以拿到锁进而执行自己的业务。

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

也就是只有sleep()方法执行结束了才会去释放锁,别的线程才能拿到锁,执行自己的业务


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

有三种方式可以停止线程

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

也就是给线程配置一个退出运行状态标志,能让run方法执行完成后正常退出

在这里插入图片描述

  1. 使用stop方法强行终止(不推荐,方法已作废)
    在这里插入图片描述

  2. 使用interrupt方法中断线程(原理和第一种是一样的)

打断阻塞的线程( sleep,wait,join )的线程,线程会抛出InterruptedException异常
打断正常的线程,可以根据打断状态来标记是否退出线程

current.isInterrupted()默认是false
只有在线程调用interrupt();方法才会将current.isInterrupted()设置为true
在这里插入图片描述


2.线程中并发安全

9.synchronized关键字的底层原理

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

synchronized锁是基于monitor锁实现的
例如这一段代码加锁之后进行反编译查看class字节码信息:
在这里插入图片描述
在这里插入图片描述

synchronized锁修饰方法代码块时底层实现上是一样的,但是在修饰方法时,不需要JVM编译出的字节码完成加锁操作,而synchronized在修饰代码块时,是通过编译出来的字节码生成的monitorenter和monitorexit指令来实现的。

Monitor(监视器):结构包括三部分

Monitor 被翻译为监视器,是由jvm提供,c++语言实现

  1. Owner:存储当前获取锁的线程的,只能有一个线程可以获取
  2. EntryList:关联没有抢到锁的线程,处于Blocked状态的线程
  3. WaitSet:关联调用了wait方法的线程,处于Waiting状态的线程
    在这里插入图片描述
    可参考链接【Java并发】synchronized关键字的底层原理-锁的升级

10.谈谈 JMM(Java内存模型)

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

通俗的来说,就是保证不同的线程对共享内存的值进行改变是的透明的(也就是当两个线程同时拿到共享内存的一个变量,其中一个线程对变量进行了更改,那么此时就会和共享内存做一个同步操作,然后共享内存会对所有拿到这个变量的线程做出一个同步操作)

在这里插入图片描述
总结:

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

11.什么是CAS?

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

CAS 底层实现
依赖于一个 Unsafe 类来直接调用操作系统底层的 CAS 指令
在这里插入图片描述
乐观锁和悲观锁

  • CAS
    是基于乐观锁的思想:最乐观的估计,不怕别的线程来修改共享变量,就算改了也没关系,改了反正要同步到主内存的,别的线程CAS失败可以进行自旋在拷贝一份主内存的共享变量数据,再执行自己的业务。
  • synchronized
    是基于悲观锁的思想:最悲观的估计,得防着其它线程来修改共享变量,我上了锁你们都别想改,我改完了解开锁,你们才有机会。

总结:

  • CAS的全称是: Compare And Swap(比较再交换);它体现的一种乐观锁的思想,在无锁状态下保证线程操作数据的原子性。
  • CAS使用到的地方很多:AQS框架、AtomicXXX类
  • 在操作共享变量的时候使用的自旋锁,效率上更高一些
  • CAS的底层是调用的Unsafe类中的方法,都是操作系统提供的,其他语言实现

CAS缺点:

  1. ABA问题:

如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际上却变化了

ABA问题的解决思路就是使用版本号。

在变量前面追加上版本号,每次变量更新的时候把版本号加一,那么A-B-A 就会变成1A-2B-3A。

  1. 循环时间长开销大:

如果CAS不成功,则会原地自旋,如果长时间自旋会给CPU带来非常大且没必要的开销。

可以破坏掉for死循环,当超过一定时间或者一定次数时,return退出。

  1. 只能保证一个共享变量的原子操作

当对一个共享变量执行操作时,我们可以使用循环CAS的方式来保证原子操作,但是对多个共享变量操作时,循环CAS就无法保证操作的原子性,这个时候就可以用锁,或者有一个取巧的办法,就是把多个共享变量合并一个共享变量来操作。


12.请谈谈你对 volatile 的理解

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

12.1.保证线程间的可见性

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

在这里插入图片描述
解决方案一(不推荐):在程序运行的时候加入vm参数-Xint表示禁用即时编译器,不推荐,得不偿失(其他程序还要使用)

解决方案二:在修饰stop变量的时候加上volatile,当前告诉 jit不要对 volatile 修饰的变量做优化

12.1.禁止进行指令重排序

用 volatile 修饰共享变量会在读、写共享变量时加入不同的屏障,阻止其他读写操作越过屏障,从而达到阻止重排序的效果
例如下面的代码在并发环境中,由于存在多个线程同时访问共享变量的情况,可能会导致可见性问题和指令重排等影响程序正确性的行为。
在这里插入图片描述
解决办法就是在变量上添加volatile禁止指令重排序,则可以解决问题
在这里插入图片描述
当然也不能随便加volatile关键字,要根据实际情况去加。如果都禁用了,指定效率肯定不高。


13.什么是AQS?

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

所谓抽象,其实目的就是把具体的逻辑交给子类去实现,这样就可以实现不同的特性的锁:
例如:AQS常见的实现类
ReentrantLock 阻塞式锁
Semaphore 信号量
CountDownLatch 倒计时锁

AQS内部维护了一个先进先出的双向队列,队列中存储的排队的线程
在AQS内部还有一个属性state,这个state就相当于是一个资源默认是0(无锁状态),如果队列中的有一个线程修改成功了state为1,则当前线程就相等于获取了资源
在对state修改的时候使用的cas操作,保证多个线程修改的情况下原子性
参考链接:【Java并发】什么是AQS?


14.ReentrantLock的实现原理

ReentrantLock表示支持重新进入的锁,调用 lock 方 法获取了锁之后,再次调用 lock,是不会再阻塞
ReentrantLock主要利用CAS+AQS队列来实现
支持公平锁和非公平锁,在提供的构造器的中无参默认是非公平锁,也可以传参设置为公平锁

构造方法接受一个可选的·公平参数(默认非公平锁),当设置为true时,表示公平锁否则为非公平锁。公平锁的效率往往没有非公平锁的效率高,在许多线程访问的情况下,公平锁表现出较低的吞吐量。

参考链接:【Java并发】ReentrantLock的实现原理


15.synchronized和Lock有什么区别 ?

语法层面
synchronized 是关键字,源码在jvm 中,用 c++ 语言实现
Lock 是接口,源码由 jdk 提供,用 java 语言实现(API)
使用 synchronized 时,退出同步代码块锁会自动释放,而使用 Lock 时,需要手动调用 unlock 方法释放锁

功能层面
二者均属于悲观锁、都具备基本的互斥、同步、锁重入功能
Lock 提供了许多 synchronized 不具备的功能,例如
公平锁(参考ReentrantLock)
可打断
在这里插入图片描述在这里插入图片描述

可超时
在这里插入图片描述

也就是使用tryLock()时加入时间参数,如果超过这个时间拿不到锁,就自动放弃抢锁(放弃阻塞),反之在规定时间能抢到锁,那就正常执行自己的逻辑

多条件变量
在这里插入图片描述

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

性能层面
没有竞争时,synchronized 做了很多优化,如偏向锁、轻量级锁,性能不赖
竞争激烈时,Lock 的实现通常会提供更好的性能


16.死锁产生的条件是什么?

产生的四个必要条件如下:(缺一不可)

  1. 互斥条件:一个资源同一时间能且只能被一个线程访问;
  2. 不可掠夺:当资源被一个线程占用时,其他线程不可抢夺该资源;
  3. 请求与等待:当资源被一个线程占用时,其他线程只能等待资源的释放再拥有;
  4. 循环等待:指的是若干线程形成头尾相接的情况,将所有资源都占用导致的整体死锁或局部死锁。

一个线程需要同时获取多把锁,这时就容易发生死锁

前三条其实就是作为锁的条件,第四条(循环等待)就是造成死锁的主要原因

循环等待也就是双方的锁都锁住了对方,并且都在等待对方的解锁,造成死循环(类似springbean的循环依赖)
在这里插入图片描述
如何进行死锁诊断?

  1. 命令查看(jps+jstack)
  2. jconsole工具
  3. VisualVM:故障处理工具

参考链接:【Java并发】如何进行死锁诊断?


17.聊一下ConcurrentHashMap

ConcurrentHashMap 是一种线程安全的高效Map集合
底层数据结构:

  • JDK1.7底层采用分段数组+链表实现
  • JDK1.8 采用的数据结构跟HashMap1.8的结构一样,数组+链表/红黑二叉树。

JDK1.7中ConcurrentHashMap:
采用分段数组+链表实现
在这里插入图片描述
Segment数组的每一个元素都存储这一个HashEntry 数组的地址值,并且segment数组定义好了就不能扩容了。

向ConcurrentHashMap添加元素的流程
在这里插入图片描述
底层使用了ReentrantLock锁保证并发下的线程安全。

但是这种方式效率并不高,每一次添加元素进去都要枷锁,解锁。效率不高

JDK1.8中ConcurrentHashMap
在JDK1.8中,放弃了Segment臃肿的设计,数据结构跟HashMap的数据结构是一样的:数组+红黑树+链表

  1. 采用 CAS + Synchronized来保证并发安全进行实现
  2. CAS控制数组节点的添加(CAS操作保证一个共享变量的原子操作
  3. synchronized只锁定当前链表红黑二叉树的首节点,只要hash不冲突,就不会产生并发的问题 , 效率得到提升
    在这里插入图片描述
    总结:
    1. 底层数据结构:
    JDK1.7底层采用分段的数组+链表实现
    JDK1.8 采用的数据结构跟HashMap1.8的结构一样,数组+链表/红黑二叉树
    2. 加锁的方式
    JDK1.7采用Segment分段锁,底层使用的是ReentrantLock
    JDK1.8采用CAS添加新节点,采用synchronized锁定链表红黑二叉树的首节点,相对Segment分段锁粒度更细性能更好

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

Java并发编程三大特性

1. 原子性(加锁)
一个线程在CPU中操作不可暂停,也不可中断,要不执行完成,要不不执行
在这里插入图片描述

  1. 可见性(共享变量加volatile关键字)
    内存可见性:让一个线程对共享变量的修改对另一个线程可见
    在这里插入图片描述

  2. 有序性(共享变量加volatile关键字)—会在读、写共享变量时加入不同的屏障
    指令重排:指令重排虽然在单个线程内保持了语义一致性,但在多线程环境下,并发读写操作的顺序可能被改变,从而引发问题。例如,在多线程中对共享变量进行读取和写入操作时,如果指令重排改变了读取和写入的顺序,并且没有适当的同步机制来保证顺序性,就可能导致线程读取到失效的数据或产生不符合预期的结果。
    在这里插入图片描述


3.线程池

资源管理:线程池可以有效地管理系统中的线程资源。线程创建和销毁的开销比较大,如果在每个任务执行时都手动创建和销毁线程,会产生较高的开销。而线程池可以在程序启动时预先创建一定数量的线程,并对其进行复用,避免了线程频繁的创建和销毁,从而提高了系统性能和资源利用率。

控制线程数量:线程池可以限制同时执行的线程数量,可以通过设置线程池的大小来控制并发度。这样可以避免线程数量过多导致系统负载过重,以及线程数量过少导致资源浪费。线程池会自动管理线程的调度和执行,保证线程数量在合理范围内。

提高响应速度:线程池可以提高任务的响应速度。当有新的任务到达时,线程池中的空闲线程可以立即执行任务,而不需要等待新线程的创建。这样可以降低任务的等待时间,提高整体的响应性能。

避免资源竞争:线程池可以避免由于资源竞争而引起的性能问题。线程池可以通过适当的同步机制来管理共享资源的访问,避免多个线程同时对共享资源进行修改而导致的竞争和冲突。

统一管理和监控:线程池可以提供统一的管理和监控接口,方便对线程的状态、执行情况、异常处理等进行统一管理和监控。可以通过线程池的API来获取线程池中线程的状态或取消执行中的任务等操作。

19.说一下线程池的核心参数(线程池的执行原理知道嘛)

在这里插入图片描述

在这里插入图片描述

  • corePoolSize 核心线程数目
  • maximumPoolSize 最大线程数目 = (核心线程+救急线程的最大数目)
  • keepAliveTime 生存时间 - 救急线程的生存时间,生存时间内没有新任务,此线程资源会释放
  • unit 时间单位 - 救急线程的生存时间单位,如秒、毫秒等
  • workQueue - 当没有空闲核心线程时,新来任务会加入到此队列排队队列满会创建救急线程执行任务
  • threadFactory 线程工厂 - 可以定制线程对象的创建,例如设置线程名字、是否是守护线程等
  • handler 拒绝策略 - 当所有线程都在繁忙,workQueue 也放满时,会触发拒绝策略
  • 拒绝策略

1.AbortPolicy:直接抛出异常,默认策略
2.CallerRunsPolicy:用调用者所在的线程来执行任务;(调用主线程来完成任务)
3.DiscardOldestPolicy:丢弃阻塞队列中靠最前(待在队列最久的任务)的任务,并执行当前任务;
4.DiscardPolicy:直接丢弃任务;

线程池线程执行流程:
在这里插入图片描述

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

workQueue - 当没有空闲核心线程时新来任务会加入到此队列排队队列满会创建救急线程执行任务
阻塞队列有四种:(1,2常用,3,4了解即可)
1.ArrayBlockingQueue:基于数组结构的有界阻塞队列,FIFO(先进先出)。
2.LinkedBlockingQueue:基于链表结构的有界阻塞队列,FIFO。
3.DelayedWorkQueue :是一个优先级队列,它可以保证每次出队的任务都是当前队列中执行时间最靠前的
4.SynchronousQueue:不存储元素的阻塞队列,每个插入操作都必须等待一个移出操作。

ArrayBlockingQueue的LinkedBlockingQueue区别其实也就是数组和链表的区别以及有界无界和出入队列锁的数量不同
在这里插入图片描述
注意:

  1. LinkedBlockingQueue建议一般设置有界(虽然也可以无界,但不推荐)

在这里插入图片描述

  1. LinkedBlockingQueue他的出队和入队是两把不同的锁,相比ArrayBlockingQueue一把锁。灵活度高

在这里插入图片描述

  1. LinkedBlockingQueue因为是链表,只有在任务加入到队列时才会创建node任务节点。而ArrayBlockingQueue在队列创建之初就初始化长度了。

21.如何确定核心线程数

CPU核数指的是物理核心的数量,而线程数包括物理核心和虚拟核心的总数。在多核处理器中,线程数通常等于核心数,而在带有超线程技术的处理器中,线程数可以大于核心数。

高并发、任务执行时间短 ( CPU核数+1 ),减少线程上下文的切换

并发不高、任务执行时间长

IO密集型的任务 (CPU核数 * 2 + 1)(java程序通常是这种)
计算密集型任务 ( CPU核数+1 )

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

22.线程池的种类有哪些

  1. newFixedThreadPool(固定线程数线程池):创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待
    在这里插入图片描述
    适用于任务量已知,相对耗时的任务

无需救急,人人有份,相当于KFC知道今天会有多少个顾客来点餐,那KFC事先备好餐品的数量。

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

在这里插入图片描述适用于按照顺序执行的任务

KFC只有一个窗口,排队取餐,来一个人点完单不做,先滚后面排队去,到你了才给你做餐

  1. newCachedThreadPool(可缓存线程池):创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程
    在这里插入图片描述
    适合任务数比较密集,但每个任务执行时间较短的情况

KFC有0元领鸡腿活动,鸡腿做很快,来一个单先做好这个单的鸡腿,在接下一个单。并且做鸡腿的都是临时员工

  1. newScheduledThreadPool(“延迟”和“周期执行”):可以执行延迟任务的线程池,支持定时及周期性任务执行

相当于提前预定,到了预定时间就去做餐,或者接到单了,但是先不做,可以摸鱼晚点做

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

参考阿里开发手册《Java开发手册-嵩山版》
在这里插入图片描述
其实就是,使用Executors创建的线程池要么就是阻塞队列太长了,要么就是允许创建的线程数量最大化,都会导致堆积问题,导致堆内存溢出错误(OMM)

推荐使用(根据实际业务情况,定制化线程池)
使用 ThreadPoolExecutor类来手动创建线程池,并根据实际需求进行配置,以更好地控制线程池的行为。通过自定义线程池的参数,例如核心线程数、最大线程数、队列容量和拒绝策略等,可以更好地适应不同的业务场景,并避免上述潜在问题。
在这里插入图片描述

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

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

相关文章

如何将Linux上的cpolar内网穿透设置成 - > 开机自启动

如何将Linux上的cpolar内网穿透设置成 - > 开机自启动 文章目录 如何将Linux上的cpolar内网穿透设置成 - > 开机自启动前言一、进入命令行模式二、输入token码三、输入内网穿透命令 前言 我们将cpolar安装到了Ubuntu系统上,并通过web-UI界面对cpolar的功能有…

如何维护自己的电脑

目录 1、关于电脑选择的建议 1.1、价格预算 1.2、明确需求 1.3、电脑配置 1.4、分辨率 1.5、续航能力 1.6、品牌选择 1.7、用户评测 1.8、各个电商平台对比 1.9、最后决策 2、我的选择 3、电脑保养 3.1 外部清洁 3.2 安装软件 3.3 优化操作系统 3.4 维护硬件设…

web前端之CSS

文章目录 一、CSS简介1.1 CSS语法规则 二、CSS的引用方法2.1 定义行内样式表2.2定义内部样式表2.3链入外部样式表2.4导入外部样式表 三、CSS选择符3.1 基本选择符3.1.1 标签选择符3.1.2 class类选择符3.1.3 id选择符 3.2 复合选择符3.2.1 交集选择符(合并选择器&…

Docker安装Hadoop分布式集群

一、准备环境 docker search hadoop docker pull sequenceiq/hadoop-docker docker images二、Hadoop集群搭建 1. 运行hadoop102容器 docker run --name hadoop102 -d -h hadoop102 -p 9870:9870 -p 19888:19888 -v /opt/data/hadoop:/opt/data/hadoop sequenceiq/hadoop-do…

将matlab中工作区的数据保存为.mat文件及加载.mat数据

将matlab工作区中的数据保存为.mat文件 如数据a a[1 1 2 3 2 4];一、工作区数据 二、保存为.mat文件 利用save保存数据a到data.mat文件中 save(data.mat,a);三、加载数据 Iload(data.mat)

SEO搜索引擎优化

目录 场景 内部业务To B (Business-to-Business,B2B)需要降低SEO,反爬 客户业务To C (Business-to-Consumer,B2C)需要提高SEO TDK优化 Title(标题) Description(描述) Keywords&#xff…

matplotlib fig.legend()常用参数 包括位置调整和字体设置等

一、四种方法 legend() legend(handles, labels) legend(handleshandles) legend(labels)1 legend() labels自动通过绘图获取(Automatic detection of elements to be shown in the legend) # 第一种方法 ax.plot([1, 2, 3], labelInline label) ax.l…

Redis过期键删除策略

如果一个键过期了,那么它什么时候会被删除呢? 这个问题有三种可能的答案,它们分别代表了三种不同的删除策略: 1.定时删除:在设置键的过期时间的同时,创建一个定时器(timer),让定时器在键的过期时间来临时…

4.3 移动终端安全

数据参考:CISP官方 目录 移动智能终端重要性移动智能终端安全威胁移动智能终端安全使用 一、移动智能终端重要性 1、移动智能终端的发展 完整的超小型计算机系统 强大的处理能力完整的软硬件系统 可完成较为复杂的处理任务 拍照、听音乐、玩游戏、上网、视…

免费ai写作生成器帮你释放创作天赋

喂!听说你想提升写作功力?那么恭喜你,现在流行的ai写作软件将成为你提升写作效率的秘密武器。这是一款革命性的应用,就像你的个人写作导师,会帮助你通过简单的几步,创造出令人瞠目结舌的文字作品&#xff0…

arcgis更改图层字段名脚本

话不多说,上脚本源码,复制黏贴即可 #-*- coding:utf-8 -*- __author__ lumen import arcpy #输入图层 InputFeature arcpy.GetParameterAsText(0) #原始字段 oldField arcpy.GetParameterAsText(1) # 获取原始字段类型 oldFieldType desc arcpy.…

python人工智能可以干什么,python人工智能能干什么

大家好,给大家分享一下python做人工智能需要什么水平,很多人还不知道这一点。下面详细解释一下。现在让我们来看看! 人工智能包含常用机器学习和深度学习两个很重要的模块,而python拥有matplotlib、Numpy、sklearn、keras等大量的…

Linux Linux系统上C程序的编译与调试

一、环境配置 在Linux操作系统中,打开终端,以管理员root模式登录 1.更新:输入命令apt update 2.下载vim:输入命令apt install vim -y 3.下载gcc:输入命令apt install gcc -y 4.下载g:输入命令apt install …

VR内容研发公司 | VR流感病毒实验虚拟现实课件

由广州华锐互动开发的《VR流感病毒实验虚拟现实课件》是一种新型的教学模式,可以为学生提供更加真实和直观的流感病毒分离鉴定实验操作体验,从而提高学生的实验技能和工作效率。 《VR流感病毒实验虚拟现实课件》涉及了生物安全二级实验室(BSL-2)和流感病…

ElasticSearch:项目实战(2)

ElasticSearch: 项目实战 (1) 需求&#xff1a; 新增文章审核通过后同步数据到es索引库 1、文章服务中添加消息发送方法 在service层文章新增成功后&#xff0c;将数据通过kafka消息同步发送到搜索服务 Autowiredprivate KafkaTemplate<String,String> kafkaTemplate;/…

Java整合Selenium录制视频

捕捉视频 有时候我们未必能够分析故障只需用日志文件或截图的帮助。有时捕获完整的执行视频帮助。让我们了解如何捕捉视频。 我们将利用Monte媒体库的执行相同。 配置 第1步&#xff1a;导航到URL下载屏幕记录JAR&#xff0c;如下图所示。 http://www.randelshofer.ch/monte…

linux环形缓冲区kfifo实践3:IO多路复用poll和select

基础知识 poll和select方法在Linux用户空间的API接口函数定义如下。 int poll(struct pollfd *fds, nfds_t nfds, int timeout); poll()函数的第一个参数fds是要监听的文件描述符集合&#xff0c;类型为指向struct pollfd的指针。struct pollfd数据结构定义如下。 struct poll…

如何让PPT看起来规整统一

一、字体 常见问题&#xff1a;字体风格太多、文字可读性差、页面风格不匹配 1.使用文字的几个原则 &#xff08;1&#xff09;一份PPT最多使用两种中文字体 比如首页大标题宋体、正文黑体、其他页标题黑体加粗。通过粗细、字号、不同颜色背景等区分不同层级。注意 使用粗体…

【React学习】—jsx语法规则(三)

【React学习】—jsx语法规则&#xff08;三&#xff09; 一、jsx语法规则&#xff1a; 1、定义虚拟DOM&#xff0c;不要写引号&#xff0c; 2、标签中混入JS表达式要用{} 3、样式的类名指定不要用class&#xff0c;要用className 4、内联样式&#xff0c;要用style{{key:value}…

AWS中Lambda集成SNS

1.创建Lambda 在Lambda中&#xff0c;创建名为AWSSNSDemo的函数 use strict console.log(loading function); var aws require(aws-sdk); var docClient new aws.DynamoDB.DocumentClient(); aws.config.regionap-southeast-1;exports.handler function(event,context,cal…