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

线程基础知识(三)

前言

之前两篇文章介绍了线程的基本概念和锁的基本知识,本文主要是学习同步机制,包括使用synchronized关键字、ReentrantLock等,了解锁的种类,死锁、竞争条件等并发编程中常见的问题。

一、关键字synchronized

  1. synchronied关键字可以把任意一个非null的对象当做锁,属于独占式的悲观锁。同时属于可重入锁
  2. 早期的的synchronized属于重量级的锁,效率低下,因为监视器是依赖底层的操作系统Lock实现的,从6之后java对sychronized进行了优化,jdk1.6以后还引入了 大量的优化,比如自旋锁,适应性锁,锁消除,锁粗化,偏向锁,轻量级锁等。

1.synchronized用法

常用来保证代码的原子性,主要有三种使用方法

  • 修饰实例:作用于当前的对象实例加锁,进入同步代码前获得,当前对象实例的锁
synchronized void method() {
//业务代码
}
  • 修饰静态方法: 也就是给当前类加锁,会作用于该类所有的对象实例。如果线程A调用一个实例对象的非静态synchronized方法,而线程B需要调用这个实例对象所属类的静态synchronized方法,是允许的,不会发生互斥现象,因为静态synchronized方法是占用的锁是当前类的锁,而访问非静态synchronized方法占用的锁是当前实例对象的锁。
synchronized void staic method() {
//业务代码
}
  • 修饰代码块: 指定加锁对象,对给定的对象/类加锁,synchronized(this object)表示进入同步前要获得给定对象的锁,synchronized(类.class)表示进入同步前要获得给定类class的锁
synchronized(this) {
//业务代码
}

2. synchronized实现原理

  • 使用synchronized是不用我们去加锁和释放lock,unlock,是jvm已经代替去做了
  • synchronized修饰代码块的时候,jvm是使用monitorenter和monitorexit两个指令实现的(监视器)
    在这里插入图片描述
  • 当修饰同步方法,jvm采用ACC_SYNCHRONIZED标记符来实现的同步, 这个标识表面了这是一个同步方法

在这里插入图片描述

3.synchronized锁住的原理

monitorenter,monitorexit,ACC_SYNCHRONIZED都是基于monitor(监视器)
所谓的Monitor其实是一种同步工具,也可以说是一种同步机制。在Java虚拟机(HotSpot)中,Monitor是由
ObjectMonitor实现的,可以叫做内部锁,或者Monitor锁。
ObjectMonitor的工作原理:
ObjectMonitor有两个队列:WaitSet、EntryList,用来保存ObjectWaiter 对象列表。
_owner,获取 Monitor 对象的线程进入 _owner 区时, _count + 1。如果线程调用了wait() 方法,此时会释放Monitor 对象, _owner 恢复为空, _count - 1。同时该等待线程进入 _WaitSet 中,等待被唤醒。
-同步是锁住的

  • monitorenter,在判断拥有同步标识 ACC_SYNCHRONIZED 抢先进入此方法的线程会优先拥有 Monitor 的owner ,此时计数器+1。
  • monitorexit,当执行完退出后,计数器-1,归 0 后被其他进入的线程获得

4.除了原子性,synchronized的可见性和有序性,可重入性怎么实现

  1. 可见性:线程加锁前,将清空工作内存中共享变量的值,从而使用共享变量的时候,需要从主内存中重新读取最新的值。线程加锁后,其他线程无法获得主内存中的共享变量的值,线程解锁前必须把共享变量的最新值刷新到主内存中。
  2. 有序性:synchronized同步的代码块具有排他性,一次只能被一个线程拥有,所以可以保证同一个时刻,代码是单线程执行的,因为as-if-serial存在,单线程语句是能够保证最终结果是有序的,但是不保证不会进行指令重排,所以synchronized是保证有序是执行结果的有序而不是防止指令重排的有序性。
  3. 可重入性:synchronized是可重入锁,也就说允许一个线程二次请求自己持有的锁的临界资源,这种情况就是可重入锁,锁对象有个计数器,会记录线程获取锁的次数,当执行完对应的代码后,计数器就会减去1,只有归零就会释放锁。之所以可以重入就是因为这个计数器。

5.synchronized和ReentrantLock的区别

可从锁的实现、功能特点、性能维度等分析

  • 锁的实现:synchronized是通过jvm实现,是java的关键字;而reentrantlock是通过jdk层面的api实现的的(一般是lock()和unlock()方法配合try/catch/finally语句实现)

  • 性能:jdk1.6前synchronized性能比较差,应该都是要通过底层调用,但是1.6以后增加了适应性自旋,锁消除等,两者性能差不多。

  • 功能特点:-

    • ReentrantLock比synchronized增加了一些高级功能,如等待中断,可实现公平锁,可实现选择性通知;
    • synchronized只能是非公平锁(内部锁),- ReentrantLock可以指定是公平还是非公平(公平锁就是先等待的线程先获得锁);
    • synchronized与wait()和notify()/notifyAll()方法结合实现等待/通知机制,ReentrantLock类借助Condition接口与newCondition()方法实现。
    • ReentrantLock需要手工声明来加锁和释放锁,一般跟finally配合释放锁。而synchronized不用手动释放锁

在这里插入图片描述

二、锁类型

锁可以分为

  • 悲观、乐观锁
  • 独享、共享锁
  • 互斥锁、读写锁
  • 可重入锁
  • 公平锁、非公平锁
  • 分段锁
  • 偏向锁,轻量级锁、重量级锁
  • 自旋锁

以上是锁的名词,有的是指锁的状态,有的是锁特性或者设计。

1.乐观锁、悲观锁

乐观锁和悲观锁并不是两种特定类型锁,是人们定义的概念或者思想。主要是指人们看待同步的角度。

  • 乐观锁:顾名思义就是乐观的认为每次取数据,别人都不会修改,所以不上锁,但是在更新的时候会去判断在此期间别人有没有取更新这个数据,可以使用版本号等机制,乐观锁适用于多读的应用程序,这样可以提高吞吐量,在java中原子变量类就是使用了乐观锁的一种实现方式CAS(compare and swap 比较并交换)来实现的
  • 悲观锁:总是假设每次去获取数据,都认为别人会修改,所以每次拿取数据都会进行上锁,这样别人拿取数据就会阻塞,直到拿到锁才行,比如Java里面的关键字synchronized实现就是悲观锁,悲观锁适合写操作多的场景

①. 乐观锁:乐观锁适合读多的场景,不加锁会代理大量的性能提升 ,在java编程中是无锁编程,常常采用的是CAS算法。典型的例子就是原子类,通过CAS自旋实现原子的更新操作。
乐观锁更新判断其他线程有没有更新共享变量 一般采用数据版本机制或者CAS操作实现
(1):数据版本机制:一般两种方式,一种是使用版本号,另一个是使用时间戳方式。
版本号方式:一般是在数据表上加上一个数据版本号version字段,表示更新的次数,当数据被更新的时候计数加一,当线程A更新数据时候,会在读取数据的同时也会读取version字段,在更新提交的时候,若刚才的读取的version和数据库中的version相等才会更新,否则会重新进行更新操作。直到更新成功。

update table set xxx=#{xxx}, version=version+1 where id=#{id} and version=#{version};

(2):CAS操作:当多个线程尝试使用CAS同时更新一个变量时候,只有一个线程能够更新变量,其他线程并不会被挂起,会收到通知失败,并可以再次尝试。
CAS需要三个字段值:1.需要读写的内存位置(V)、进行比较的预期原值(A)和拟写入的新值(B),如果内存位置的V值和预期原值A想匹配,那么就会更新B,否则不做变动。

②:悲观锁:悲观锁认为对于同一个数据的并发操作,一定会发生修改的,哪怕没有修改,也会认为修改。因此对于同一份数据的并发操作,悲观锁采取加锁的形式。悲观的认为,不加锁并发操作一定会出问题。在对任意记录进行修改前,先尝试为该记录加上排他锁(exclusive locking)。如果加锁失败,说明该记录正在被修改,那么当前查询可能要等待或者抛出异常。具体响应方式由开发者根据实际需要决定。如果成功加锁,那么就可以对记录做修改,事务完成后就会解锁了。期间如果有其他对该记录做修改或加排他锁的操作,都会等待我们解锁或直接抛出异常。

2.独享锁、共享锁

独享锁是指该锁只能被一个线程获取,共享锁是指该锁可以被多个线程持有。
对于java而言ReentrantLock是独享锁,但是对于另一个lock的实现类ReadWriterLock来说,其读是共享锁,其写是独占锁。独享锁和共享锁是通过AQS来实现的,通过不同的方法,来实现独享或者共享(synchronized是独占锁)

AQS:AbstractQueueSynchronized抽象同步队列,简称AQS;它是java并发包的基础,并发的锁就是基于Aqs实现的。

  • AQS是基于一个FIFO的双向队列,其内部定义了一个node节点类,node节点内部的SHARED用来标记该线程是获取共享变量时被阻挂起后放入AQS队列的,EXCLUSIVE用来标记线程是独占资源时被挂起放入AQS队列。

  • AQS使用一个volatile修饰的int类型的成员变量state来表示同步状态,修改同步状态成功表示获得锁,volatile保证了变量在线程之间的可见性,修改state通过CAS机制来保证修改的原子性。

  • 获取state方式有两种,独占和共享。一个线程使用了独占的方式,那么其他线程就失败会被阻塞;一个线程使用共享时获取资源,另一个线程还可以通过CAS的方式进行获取。

  • 如果共享资源被占用,需要一定的阻塞等待唤醒机制来保证锁的分配,AQS会将获取共享资源失败的线程添加到一个变体的CLH中。

  • 在这里插入图片描述

    AQS中的ClH变体等待队列特性

  • AQs中队列是个双链表,也是符合FIFO先进先出的特性。

  • 通过head、tail两个头尾节点来组成队列结构,通过volatile来保证可见性。

  • Head指向的节点本身已经获得了锁,是一个虚拟节点,节点本身不具备具体线程

  • 获取不到同步状态,会将节点进行自旋获取锁,自旋一定次数失败后,会将线程阻塞,相对于CLH队列性能较好。

3.互斥锁/读写锁

  • 讲的独享锁/共享锁就是一种广义的说法,互斥锁/读写锁就是具体的实现。
  • 互斥锁在Java中的具体实现就是ReentrantLock。
  • 读写锁在Java中的具体实现就是ReadWriteLock:对资源读取和写入的时候拆分为2部分处理,读的时候可以多线程一起读,写的时候必须同步地写。

4.可重入锁:可重入锁又名递归锁,是指在同一个线程在外层获锁的时候,在进入内存自动获取锁。也就是在执行对象中所有的同步方法不用再次获取锁。 对于Java ReetrantLock而言,从名字就可以看出是一个重入锁,其名字是Reentrant Lock 重新进入锁。对于Synchronized而言,也是一个可重入锁。可重入锁的一个好处是可一定程度避免死锁。

synchronized void setA() throws Exception{Thread.sleep(1000);setB();
}synchronized void setB() throws Exception{Thread.sleep(1000);
}
上面的代码就是一个可重入锁的一个特点。如果不是可重入锁的话,setB可能不会被当前线程执行,可能造成死锁。

4. 公平锁和非公平锁

  • 公平锁是指多个线程按照锁的申请顺序来获取锁,按等待时间来获取锁,等待时间长的线程有优先获取锁的权利。
  • 非公平锁就是不是获取锁的顺序不是按照申请锁的顺序,有可能后申请的先执行,有可能会造成优先级反转或者饥饿现象。
  • 对于Java ReetrantLock而言,通过构造函数指定该锁是否是公平锁,默认是非公平锁。非公平锁的优点在于吞吐量比公平锁大
  • 对于Synchronized而言,也是一种非公平锁。由于其并不像ReentrantLock是通过AQS的来实现线程调度,所以并没有任何办法使其变成公平锁

5.分段锁

分段锁是一种设计,并不是具体的一种锁,对于ConcurrentHashMap而言是最好的例子,其并发就是通过分段式锁来实现的
在这里插入图片描述

  • ConcurrentHashMap实现原理:内部分为了若干的小的hashmap,称为段(segment),默认情况下一个ConcurrenthashMap
    分为16段,即就是锁的并发度,如果需要在ConcurrenthashMap中添加key-value,并不是将整个都加锁,而是 首先根据hashcode计算出key-value应该存放在那个段中,然后对该段加锁,并完成put操作,在多线程操作中,如果多个线程进行put操作,只要被加入的key-value不在同一个段中,则线程就可以实现真正的并行。
  • 线程安全:ConcurrentHashMap 是一个 Segment 数组, Segment 通过继承ReentrantLock 来进行加锁,所以每次需要加锁的操作锁住的是一个 segment,这样只要保证每个 Segment 是线程安全的,也就实现了全局的线程安全
  • 6.偏向锁/轻量锁/重量级锁

java每个对象都可以作为锁,锁有四种基本:无锁、偏向锁、轻量级锁、重量级锁,并且锁可以进行升级不能下降,这三种是指锁的状态,并且是针对synchronized的,是在java5,jdk1.6后引入实现高效升级synchronized,这三种锁通过对象监视器在对象头中的字段表明。

  • 偏向锁:是指一段同步代码一直被一个线程所访问,那么该线程会自动获取锁。降低获取锁的代价。
    在一段时间内,锁不存在多线程竞争, 而是总是由同一个线程多次获得,为了让线程获取锁的代价更低就引入了偏向锁的概念。怎么理解偏向锁呢? 当一个线程访问加了同步锁的代码块时,会在对象头中存储当前线程的 ID,后续这个线程进入和退出这段加了同步锁的代码块时,不需要再次加锁和释放锁。而是直接比较对象头里面是否存储了指向当前线程的偏向锁。如果相等表示偏向锁是偏向于当前线程的,就不需要再尝试获得锁了。
  • 轻量级锁:是指当锁是偏向锁的时候,被另一个线程所访问,偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,不会阻塞,提高性能。
    -重量级锁:是指当锁为轻量级锁的时候,另一个线程虽然是自旋,但自旋不会一直持续下去,当自旋一定次数的时候,还没有获取到锁,就会进入阻塞,该锁膨胀为重量级锁。重量级锁会让他申请的线程进入阻塞,性能降低。

7.自旋锁

在这里插入图片描述
自旋锁是一种技术,是为了让线程等待,我们只需要让线程执行一个忙循环。自旋锁是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式获取锁,这样好处是减少线程上下文切换的消耗,缺点是循环会消耗cpu
自旋锁是一种非阻塞锁,核心就是自旋两个字,即用自旋代替阻塞操作,某一个线程尝试获取锁的时候,如果该锁已经被另一个线程占用,那么这个这个线程将不断循环进行检查该锁是否被释放((默认次数是10,可以使用-XX:PreBlockSpinsh参数设置该值)),而不是让此线程挂起或者睡眠,一旦另一个线程释放锁那么此线程就会立即获得锁。自旋是一种忙等待状态,过程会一直消耗cpu的时间片。

8.可中断锁

在等待锁的过程中可以中断。

9.死锁

死锁是一种现象,程A持有资源x,线程B持有资源y,线程A等待线程B释放资源y,线程B等待线程A释放资源x,两个线程都不释放自己持有的资源,则两个线程都获取不到对方的资源,就会造成死锁。
死锁不能自行打破,所以线程死锁后,线程不能进行响应,所以要注意线程的使用并发场景。

死锁形成条件

  1. 互斥条件:指线程对已经获取到的资源进行排他性使用。
  2. 请求并持有:指一个线程已经持有了最少一个资源,但是有提出来新的资源请求,而新资源已经被其他线程给占用,所以当前线程会被阻塞,但阻塞的同时不会释放自己持有的资源。
  3. 不可剥夺条件:指线程获取到的资源在自己使用完成之前不能被其它线程抢占,只能是自己在使用完毕后由自己进行释放。
  4. 环路等待条件:指发生死锁的时候,必然形成了一个线程------资源的环形链。

如何破坏避免形成死锁呢:

  1. 条件1互斥条件肯定不能破坏,只能是下面三个条件进行破坏
  2. 请求并持有,我们可以一次性请求所有的数据。
  3. 对于不可剥夺条件,占用部分资源进一步申请其他资源的时候,如果申请不到,可以主动释放它占有的资源,这样不可抢占这个条件就失效了。
  4. 对于环路等待条件可以按顺序进行申请资源来预防。

如何排查
可以使用jdk自带的工具排查:

  • 1.使用jps查找运行的java进程:jsp -1
  • 2.使用jstack查看线程堆栈信息
  • 3.可以利用图形化工具Jconsole,出现死锁点击面板就能看见

三、 总结

在这里插入图片描述

相关文章:

线程基础知识(三)

前言 之前两篇文章介绍了线程的基本概念和锁的基本知识,本文主要是学习同步机制,包括使用synchronized关键字、ReentrantLock等,了解锁的种类,死锁、竞争条件等并发编程中常见的问题。 一、关键字synchronized synchronied关键…...

elasticsearch系列七:聚合查询

概述 今天咱们来看下es中的聚合查询,在es中聚合查询分为三大类bucket、metrics、pipeline,每一大类下又有十几种小类,咱们各举例集中,有兴许的同学可以参考官网:https://www.elastic.co/guide/en/elasticsearch/refere…...

SQL面试题挑战11:访问会话切割

目录 问题:SQL解答: 问题: 如下为某电商公司用户访问网站的数据,包括用户id和访问时间两个字段。现有如下规则:如果某个用户的连续的访问记录时间间隔小于60秒,则属于同一个会话,现在需要计算每…...

2023“楚怡杯”湖南省赛“信息安全管理与评估“--应急响应(高职组)

2023“楚怡杯”湖南省“信息安全管理与评估”(高职组)任务书 2023“楚怡杯”湖南省“信息安全管理与评估”(高职组)任务书第一阶段竞赛项目试题第二阶段竞赛项目试题网络安全事件响应:需要环境私聊博主:2023“楚怡杯”湖南省“信息安全管理与评估”(高职组)任务书 第一…...

【Python百宝箱】Python引领制造变革:CAM技术全景解析与实战指南

Python 驭技术潮流:探索计算机辅助制造的全方位工具库 前言 在当今制造业的快速发展中,计算机辅助制造(Computer-Aided Manufacturing,CAM)技术扮演着至关重要的角色。为了提高制造效率、优化工艺流程以及实现数字化…...

【新版Hi3559AV100 旗舰8K30 AI摄像机芯片】

新版Hi3559AV100 旗舰8K30 AI摄像机芯片 一、总体介绍 Hi3559AV100是专业的8K Ultra-HD Camera SOC,它提供了8K30/4K120广播级图像质量的数字视频录制,支持8路Sensor输入,支持H.265编码输出或影视级的RAW数据输出,并集成高性能ISP…...

小样本学习idea(不断更新)

在此整理并记录自己的思考过程,其中不乏有一些尚未成熟或者尚未实现的idea,也有一些idea实现之后没有效果或者正在实现,当然也有部分idea已写成论文正在投稿,都是自己的一些碎碎念念的思考,欢迎交流。 研一上学期 9.…...

表情包搜索网站

一个非常不错的表情包搜索网站,输入关键词即可得到所有相关的表情,还可以选择套图下载,自制表情,非常给力666 可以点击下载,会新建窗口打开图片,鼠标右键“图片另存为”,下载文件名手动补充“…...

Linux账号和权限管理

目录 一、用户账号和组账号概述 1、用户账号类型 2、组账号 1.基本组(私有组) 2.附加组(公共组) 3、ID 1.UID 2.GID 4、用户和账号管理 1.文件位置 2.useradd-----创建用户 3.userdel——删除用户账号 4.usermod---修…...

Qt/QML编程学习之心得:QML和C++的相互调用(十五)

Qt下的QML说到底是类似于JavaScript的一种解释性语言,习惯了VC的MVC(Veiw+Control)的模式,那种界面视图任何事件都是和C++的cpp中处理函数一一对应,在类中也有明确的说明的。一下子玩Qt会觉得哪里对不上,比如使用QML这种节脚本语言贴了图做了layout布局,那么一个按钮的o…...

月入10.5K,专科小伙转行网优:据说每个领域都有一个“显眼包”

网络热词流行的今天,显眼包一词又上热搜。除了熟知的内娱显眼包外,其实各行业也都有自己的“显眼包”。 显眼包又叫“现眼包”看似丢人现眼,实则是个“褒义词”,他们勇敢自信,积极乐观,敢于展示自己&#x…...

Python自动化测试:选择最佳的自动化测试框架

在开始学习python自动化测试之前,先了解目前市场上的自动化测试框架有哪些? 随着技术的不断迭代更新,优胜劣汰也同样发展下来。从一开始工具型自动化,到现在的框架型;从一开始的能用,到现在的不仅能用&…...

Ubuntu16.04 安装Anaconda

步骤 1: 去官网下载安装包,链接如下: https://repo.anaconda.com/archive/ 找到对应版本下载至本地电脑,并上传至服务器。 步骤2: 通过命令解压 sh Anaconda3-2023.03-0-Linux-x86_64.sh 一路选择yes或则回车,直到安装成功出现下面画面&…...

MR实战:统计总分与平均分

文章目录 一、实战概述二、提出任务三、完成任务(一)准备数据1、在虚拟机上创建文本文件2、上传文件到HDFS指定目录 (二)实现步骤1、创建Maven项目2、添加相关依赖3、创建日志属性文件4、创建成绩映射器类5、创建成绩驱动器类6、启…...

Redux与React环境准备、实现counter(及传参)、异步获取数据

环境说明: 一:说明 在React中使用redux,官方要求安装两个其他插件:Redux Toolkit和react-redux 1. Redux ToolKit(RTK) - 官方推荐编写Redux逻辑的方式,是一套工具的集合集,简化书写方式 (简化…...

网站服务器被入侵,如何排查,该如何预防入侵呢?

在我们日常使用服务器的过程中,当公司的网站服务器被黑客入侵时,导致整个网站以及业务系统瘫痪,将会给企业带来无法估量的损失。作为服务器的维护人员应当在第一时间做好安全响应,对入侵问题做到及时处理,以最快的时间…...

应用在网络摄像机领域中的国产音频ADC芯片

IPC:其实叫“网络摄像机”,是IP Camera的简称。它是在前一代模拟摄像机的基础上,集成了编码模块后的摄像机。它和模拟摄像机的区别,就是在新增的“编码模块”上。模拟摄像机,顾名思义,输出的是模拟视频信号…...

Unity3D 安装和下载指南及汉化

Unity3D是一款强大的游戏开发引擎,为开发者提供了丰富的工具和资源,使得游戏制作变得更加简单和高效。本文将介绍Unity3D的安装和下载步骤,以帮助初学者迅速入门。 步骤一:访问Unity官网 首先,打开浏览器&#xff0c…...

【SpringCache】SpringCache详解及其使用,Redis控制失效时间

一、使用 在 Spring 中&#xff0c;使用缓存通常涉及以下步骤&#xff1a; 1、添加缓存依赖&#xff1a; 确保项目中添加了缓存相关的依赖。如果使用 Maven&#xff0c;可以在项目的 pom.xml 文件中添加 Spring Cache 的依赖。 <dependency><groupId>org.spring…...

MyBatis的基本使用及常见问题

MyBatis 前言MyBatis简介MyBatis快速上手Mapper代理开发增删改查环境准备配置文件完成增删改查查询添加修改删除 参数传递注解完成增删改查 前言 JavaWeb JavaWeb是用Java技术来解决相关Web互联网领域的技术栈。 MySQL数据库与SQL语言 MySQL&#xff1a;开源的中小型数据库。…...

【kafka】Golang实现分布式Masscan任务调度系统

要求&#xff1a; 输出两个程序&#xff0c;一个命令行程序&#xff08;命令行参数用flag&#xff09;和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽&#xff0c;然后将消息推送到kafka里面。 服务端程序&#xff1a; 从kafka消费者接收…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

如何在看板中有效管理突发紧急任务

在看板中有效管理突发紧急任务需要&#xff1a;设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP&#xff08;Work-in-Progress&#xff09;弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中&#xff0c;设立专门的紧急任务通道尤为重要&#xff0c;这能…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

2023赣州旅游投资集团

单选题 1.“不登高山&#xff0c;不知天之高也&#xff1b;不临深溪&#xff0c;不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

《C++ 模板》

目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板&#xff0c;就像一个模具&#xff0c;里面可以将不同类型的材料做成一个形状&#xff0c;其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式&#xff1a;templa…...

Axure 下拉框联动

实现选省、选完省之后选对应省份下的市区...

DiscuzX3.5发帖json api

参考文章&#xff1a;PHP实现独立Discuz站外发帖(直连操作数据库)_discuz 发帖api-CSDN博客 简单改造了一下&#xff0c;适配我自己的需求 有一个站点存在多个采集站&#xff0c;我想通过主站拿标题&#xff0c;采集站拿内容 使用到的sql如下 CREATE TABLE pre_forum_post_…...

aardio 自动识别验证码输入

技术尝试 上周在发学习日志时有网友提议“在网页上识别验证码”&#xff0c;于是尝试整合图像识别与网页自动化技术&#xff0c;完成了这套模拟登录流程。核心思路是&#xff1a;截图验证码→OCR识别→自动填充表单→提交并验证结果。 代码在这里 import soImage; import we…...

Linux入门(十五)安装java安装tomcat安装dotnet安装mysql

安装java yum install java-17-openjdk-devel查找安装地址 update-alternatives --config java设置环境变量 vi /etc/profile #在文档后面追加 JAVA_HOME"通过查找安装地址命令显示的路径" #注意一定要加$PATH不然路径就只剩下新加的路径了&#xff0c;系统很多命…...