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

java多线程之线程安全(重点,难点)

线程安全

  • 1. 线程不安全的原因:
    • 1.1 抢占式执行
    • 1.2 多个线程修改同一个变量
    • 1.3 修改操作不是原子的
    • 锁(synchronized)
      • 1.一个锁对应一个锁对象.
      • 2.多个锁对应一个锁对象.
      • 2.多个锁对应多个锁对象.
      • 4. 找出代码错误
      • 5. 锁的另一种用法
    • 1.4 内存可见性
      • 解决内存可见性引发的线程安全问题(volatile)
    • 1.5 指令重排序

由于操作系统中,线程的调度是抢占式执行的,或者说是随机的,这就造成线程调度执行时,线程的执行顺序是不确定的,虽然有一些代码在这种执行顺序不同的情况下也不会运行出错,但是还有一部分代码会因为执行顺序发生改变而受到影响,这就会造成程序出现Bug,对于多线程并发时会使程序出现bug的代码称作线程不安全的代码.

本质原因: 线程在系统中的调度是无序的/随机的(抢占式执行)

1. 线程不安全的原因:

序号线程不安全的原因
1抢占式执行(罪魁祸首)
2多个线程同时修改同一个变量
3修改操作不是原子的
4内存可见性
5指令重排序

多线程不安全的原因主要分为一下三种:

1.原子性

  • 多行指令,如果指令前后有依赖关系,不能插入其他影响自身线程执行结果的指令

2.可见性

  • 系统调用CPU执行线程内,一个线程对共享变量的修改,另一个线程能够立刻看到

3.有序性

  • 程序执行的顺序按照代码的先后顺序执行(处理器可能会对指令进行重排序)

1.1 抢占式执行

我们通过下面的代码来进行讲解:

class Demo{private static int count;//public static void countAdd(){count++;}//返回countpublic static int getCount() {return count;}
}public class ThreadDemo11 {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(()->{for (int i = 0; i < 50000; i++) {//执行50000次count++Demo.countAdd();}});Thread t2 = new Thread(()->{for (int i = 0; i < 50000; i++) {//执行50000次count++Demo.countAdd();}});//执行t1线程t1.start();//执行t2线程t2.start();//等待t1,t2线程执行完t1.join();t2.join();//打印此时的count值System.out.println(Demo.getCount());}

此时我们可以看到,线程 t1 和线程 t2 分别对count进行50000次的自增,那么我们最后打印的值应该是100000吧~

此时我们运行看一下结果:

在这里插入图片描述

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

大家会发现,每次的运行结果都不一样,并且没有一次的值是正确的,到底是为什么呢?

小鱼给大家画图解释下:

在这里插入图片描述

  • load: 从内存中将值读取到cpu寄存器中

  • add: 将cpu寄存器的值进行+1

  • save: 将寄存器的值读取到内存中

此时这里的结果错误,就是因为count++不是原子的而造成.

为什么这么说呢? 为了方便大家理解,我们用两个cpu内核来举例.内两个圆圆的东西就是 t1 的工作内存和 t2 的工作内存.

工作内存包含:cpu寄存器和缓存…

在这里插入图片描述

此时我们可以观看到,我们是在执行完 t1 线程的count++之后再去执行 t2 的count++的.此时我们的count是2,是正确的~~

但是呢,由于线程的随即调度,我们可能会存在这种情况:

在这里插入图片描述

由于线程是抢占式执行的,所以可能会存在,当 t1 线程刚进行 load 之后, t2 就也进行了 load,就是上图中左侧线程执行的顺序.当然,类似于这种插队式的组合方法多的数不清,上图运行的结果是count=1,但是我们的count已经自增两次了啊,应该是2的,此时出现的错误,就是线程安全的问题.

下面是一部分可能出现的随机排列情况:

在这里插入图片描述

1.2 多个线程修改同一个变量

上述的多线程安全问题就是因为多个线程对同一变量进行修改造成的.

大家看下面的表格:

原因安全性
一个线程修改一个变量安全
多个线程修改一个变量不安全
多个线程读取多个变量安全
多个线程修改多个不同变量安全

1.3 修改操作不是原子的

原子性: 不可分割的最小单位.

在这里插入图片描述

通过上述过程我们知道,正因为有些操作不是原子的,导致两个或多个线程的指令排序存在更多的变数,自然就引发线程不安全的问题.

关于内存可见性,和指令重排序在后面讲到…

那我们如何解决上述的线程安全问题呢?

我们通过count++ 举例,如何让count++ 变成原子的呢?

我们可以通过加锁的方式将count++ 变成原子的.

锁(synchronized)

锁的核心操作分为两个:

(1) 加锁 : 当我们进入这个房间之后,别人就无法进入这个房间.

(2) 解锁 : 只有我们打开门,释放锁之后,别人才可以进入这个房间.

如果我进入这个房间之后,还有别人想要进入,就需要等我释放锁,走出这个房间才可以进入,别人在门口等待我的过程称为"阻塞".

当然,由于线程是抢占式执行的,所以如果我想进入这个房间就需要和那些都想进入这个房间的人进行争抢,当我进入这个房间之后,此时一群人只能在外面等着我,不能干别的事情,当我出了这个房间之后,他们又会开始新一轮的争抢,如果我还有进入房间的需要,我也会再次和他们一起争抢.

锁(synchronized) 这个关键字还有一个参数需要传进去,这个参数的类型需要是object或者它的子类

1.一个锁对应一个锁对象.

关于这个锁对象的用途,这里通过生活中的例子讲解…

我们假设有两个老师,A,B他们都是教英语的,学校规定,这个学期英语课只有50节,工资按照你们每个人上课的次数决定,由于上课的教室只有一个,所以A,B老师先到先得.因为老师上课的时候不能被打扰,所以规定,这个教室一次只能进入一个老师,假设A老师在讲课,那么B老师如果想讲课的话只能等着,且不能做别的事情,只能等A老师讲完课并且出门之后,再次和A老师竞争上课的资格.

上面涉及到的知识点有:

(1) A,B老师先到先得(抢占式执行)(也可以称为锁竞争)

(2) 学校规定,一次只能进去一个老师(加锁)

(3)如果A老师讲课,B老师如果想讲课的话只能等着(阻塞)

(4) 只能等A老师讲完课并且出门之后(执行完锁内的代码块,并释放锁)

也可以用代码举例:

我们这里假设两个老师讲的课程一模一样,这50节课的内容从来没变.

class Teacher{static Object object = new Object();public static void AttendClass(){//此时两个进程都调用这个方法,为了防止老师讲课被打扰//对这个讲课进行加锁//此时这个锁的参数,也可以称为锁对象//我们可以将锁对象理解为教室,synchronized (object){//课程System.out.println("ABCDEFG....");ThreadDemo14.size--;}}
}
public class ThreadDemo14 {static int size = 50;public static void main(String[] args) {Thread A = new Thread(()->{while (size >= 0)Teacher.AttendClass();}) ;Thread B = new Thread(()->{while (size >= 0)Teacher.AttendClass();}) ;A.start();B.start();}
}

上述讲的例子是只在教室里面讲英语(只有一个锁,且只有一个锁对象).下面这个例子是不仅仅是讲英语…

2.多个锁对应一个锁对象.

依旧是先语言表达一下:

A,B两个老师,A英语老师,B语文老师,但是呢,只有一个教室可以用来上课,此时A,B老师就会为了这个教室的使用权而争抢,没有抢到的老师只能等着,依旧是50节课,谁上的课多谁工资高!

代码举例:

class Teacher{static Object object = new Object();public static void EnglishClass(){//注意这里synchronized (object){System.out.println("ABCDEFG...."+ThreadDemo14.size);ThreadDemo14.size--;}}public static void ChineseClass(){//注意这里synchronized (object){System.out.println("鹅鹅鹅,曲项向天歌...."+ThreadDemo14.size);ThreadDemo14.size--;}}
}
public class ThreadDemo14 {static int size = 50;public static void main(String[] args) {Thread A = new Thread(()->{while (size >= 0)Teacher.EnglishClass();}) ;Thread B = new Thread(()->{while (size >= 0)Teacher.ChineseClass();}) ;A.start();B.start();}
}

上述代码和之前的代码的区别就是,我上了两个锁,但是锁对象一样(多个锁,但是只有一个锁对象),这是什么意思呢? 意思就是,虽然我们讲的是不同的课程(锁的代码块不一样),但是这个锁对象一样,意味着我们需要在同一个教室讲课,一次只能有一个老师讲课.

更通俗点理解就是:不管你多少个老师,不管你教什么,只要是同一个教室(锁对象一样)那么,你就只能等这个教室空出来才能用…在此期间

2.多个锁对应多个锁对象.

但是呀,如果多个老师争抢一个教室,那么一定会引发不满的,所以个,学校就多建造了几个教室,那么这些老师就可以在不同的教室上课了…

class Teacher{
//教室1static Object classroom1 = new Object();//教室2static Object classroom2 = new Object();public static void EnglishClass(){//此时锁对象不同,意味着在不同的教室synchronized (classroom1){System.out.println("ABCDEFG...."+ThreadDemo14.size);ThreadDemo14.size--;}}public static void ChineseClass(){//此时锁对象不同,意味着在不同的教室synchronized (class2room){System.out.println("鹅鹅鹅,曲项向天歌...."+ThreadDemo14.size);ThreadDemo14.size--;}}
}

此时我们大概了解锁对象的意思了,科学一点的解释如下:

总结:
(1) 多个代码块使用了同一个同步监视器 ( 锁 ) , 锁住一个代码块的同时,也锁住所有使用该锁的所有代码块,其他线程无法访问其中任何一个代码块.

(2) 多个代码块使用了同一个同步监视器 ( 锁 ) , 锁住一个代码块的同时,也锁住了所有该锁的所有代码块,但是没有锁柱使用其他同步监视器的代码块,其他线程有机会访问其他同步监视器的代码块.

4. 找出代码错误

你也为锁这块讲完了吗?

天真! 上面还有一处错误! 不知道同学发现了没有…

我们来运行下两个英语老师的那个例子:
在这里插入图片描述

咦,怎么打印出来了-1,这是为什么呢?

有一种情况我们没有考虑到,就是…

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

那么怎么解决呢?

在这里插入图片描述
此时的运行结果:

在这里插入图片描述
可能这个方法不是最优的,因为每次进入锁又需要进行一次if(),这些都是时间上的开销!!!

5. 锁的另一种用法

我们可以用synchronized来修饰方法,如果是用锁来修饰方法的话,我们不需要给这个锁设置参数,如果这个方法是静态的,那么这个锁的对象就是类名(该方法所处的类).class,如果是非静态的方法,那么谁调用这个方法,谁就是锁对象,也就是this.

代码如下:

非静态方法:

   public  void func1(){synchronized (this){}}//两者等价synchronized public void func2(){}

静态方法:

class A1{public static void func1(){synchronized (A.class){}}//两者等价synchronized public void func2(){}}

1.4 内存可见性

什么是内存可见性呢? 大家看下面的代码,猜猜运行结果!

public class ThreadDemo15 {static boolean flog = false;public static void main(String[] args) {Thread t1 = new Thread(()->{while (!flog){//什么都不打印}//循环执行结束System.out.println("循环执行结束");});t1.start();try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}flog = true;System.out.println("flog改为true");}
}

两个选项:

A. 打印完flog之后就程序结束
B. 打印完flog之后程序没有结束

现在请看运行结果…

在这里插入图片描述

正确答案是B,为什么呢?

小鱼为大家解答.

我们通过一个例子来解释:

一天呢,玉帝派给孙悟空一个任务,要求他一直看着唐僧,看他会不会怀孕…
这孙悟空一听,男的会怀孕? 那不可能啊…

于是玉帝每次问孙悟空,孙悟空看都不看唐僧一眼就说没怀孕,不知过了多久,唐僧因为喝了女儿国的水,怀孕了!!! 就在唐僧怀孕之后,玉帝问孙悟空,你师傅怀孕了嘛?孙悟空依旧说不屑的回答:“没有”,殊不知唐僧孩子都快生出来了…

我们刚才的程序为什么会在我修改flog之后也一直在继续执行呢?

是因为,while(flog != false) 需要两步,从内存中读取flog的值到自己的寄存器,再将寄存器的值和false比较,由于呢~读内存(load)的操作很是麻烦,所以编译器就自作主张,想要优化这个代码,于是就不再去内存中读取了,直接将自己寄存器的值和false进行比较,但是这一不读取就出现了意外,代码内心: 你小子看我一眼啊,我都变了,我都变成true了,你丫还在循环!!!

上面出现线程安全的主要原因就是编译器优化,因为读内存的操作比读寄存器要慢几千倍,所以编译器为了运行效率,擅自做了决定.

所谓内存可见性就是在多线程的情况下,编译器对于代码优化,产生了误判,从而引起的一系列Bug,进而导致咱们的代码bug了.

解决内存可见性引发的线程安全问题(volatile)

我们对比这个代码:

public class ThreadDemo15 {static boolean flog = false;public static void main(String[] args) {Thread t1 = new Thread(()->{while (!flog){//什么都不打印//加入了一个时间限制try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}//循环执行结束System.out.println("循环执行结束");});t1.start();try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}flog = true;System.out.println("flog改为true");}
}

运行结果:

在这里插入图片描述

这个代码有sleep,加上sleep循环执行速度就变得很慢,当循环次数下降了,此时load不再是负担,编译器就没必要优化了.

但是我如果我就想让循环空转,并且还不能出错,该怎么处理?

咱么可以让编译器针对这个场景暂停优化.

如何做到呢?

有请接下来的主角: volatile

我们通过使用volatile关键字修饰变量,此时该变量就会禁止编译器优化,能够保证每次都是从内存中重新读取数据.

在这里插入图片描述

volatile是一个类型修饰符,作用是作为指令关键字,一般都是和const对应,确保本条指令不会被编译器的优化而忽略。

1.5 指令重排序

volatile还有一个用处就是禁止指令重排序.

指令重排序也是编译器优化的策略,调整了代码的执行顺序,让程序更高效.

前提: 保证代码逻辑不变,并且调整之后的结果要和之前是一样的.

关于指令重排序,小鱼给大家举个例子吧…

妈妈今天让小鱼去菜市场买菜,把买菜的清单列给了小鱼.
在这里插入图片描述

小鱼发现,如果按照清单上的顺序购买,比较浪费时间.

在这里插入图片描述

小鱼于是呢,就想换个路线…

在这里插入图片描述

当小鱼买完西红柿之后呢,妈妈给小鱼打电话,问小鱼买完西红柿了嘛,小鱼说买完了,妈妈说,那就抓紧回家吧~~

此时小鱼就到了家里,妈妈看到小鱼手里的西红柿陷入了沉思…

怎么只有西红柿,别的菜呢? 然后小鱼就挨打了,因为妈妈以为他是按照清单上的顺序去买的,当看到小鱼买完西红柿之后以他都买好了,就让他回来了,结果今天只能吃凉拌西红柿了…

我们也可以用代码来解释:

class Student {//成员变量static Student s;//成员方法public static Student getS() {return s;}//public static void main(String[] args) {Thread t1 = new Thread(()->{s = new Student();});Thread t2 = new Thread(()->{if(s != null) {s.getClass();}});t1.start();t2.start();}
}
s = new Studnet();

这和new的过程可以大体分为三部分.

1.申请内存空间
2.调用构造方法
3.把对象的引用赋值给 s

如果是在单线程的环境下,1,2,3的指令可以发生重排序,1先执行,2和3谁先谁后都可以.

在单线程情况下,这种优化并不会出现什么问题,但是在多线程情况下就不好说了…

在这里插入图片描述
此时呢,为了避免指令重排序产生的线程安全问题,我们需要将

   volatile static Student s;//进行volatile修饰

相关文章:

java多线程之线程安全(重点,难点)

线程安全1. 线程不安全的原因:1.1 抢占式执行1.2 多个线程修改同一个变量1.3 修改操作不是原子的锁(synchronized)1.一个锁对应一个锁对象.2.多个锁对应一个锁对象.2.多个锁对应多个锁对象.4. 找出代码错误5. 锁的另一种用法1.4 内存可见性解决内存可见性引发的线程安全问题(vo…...

如何免费使用chatGPT4?无需注册!

Poe体验真滴爽首先提大家问一个大家最关心的问题如何在一年内赚到一百万&#xff1f;用个插件给他翻译一下体验地址效果是非常炸裂的&#xff0c;那么我就将网址分分享给大家https://poe.com/前提&#xff1a;要有魔法&#xff0c;能够科学shangwangChatGPT-3 随便问GPT-4 模型…...

Android Flutter在点击事件上添加动画效果

在Android App的开发项目中&#xff0c;我们需要在点击事件上实现一个动画效果来提高用户的体验度。比如闲鱼底部中间按钮的那种。该怎么实现呢&#xff1f; 一起来看看吧 实现效果如图&#xff1a; ​实现思路 根据UI的设计图&#xff0c;对每个模块设计好动画效果&#xff0…...

VSCode嵌入式开发环境搭建

Vscode开发环境搭建 看这个链接就可以了&#xff0c;后面下载调试有点问题看下3.3。 在VSCode上部署STM32F1的开发环境 1. MXCube配置工程生成Makefile文件 借助正确的编译工具链进行编译&#xff0c; 2. 编译工具链搭建 编译工具链使用GCC的ARM版本 arm-none-eabi-gcc &am…...

数据结构之栈的使用

栈是计算机科学中一个重要的数据结构。它是一种特殊的线性表&#xff0c;只允许在一端进行进出操作。这一端被称为栈顶&#xff0c;另外一端被称为栈底。栈的特点是后进先出&#xff0c;即最后进入栈的元素会先被弹出栈。栈的应用广泛&#xff0c;例如在编译器中&#xff0c;栈…...

QMessageBox手动添加按钮并绑定按钮的信号

视频展示效果&#xff08;结合代码看效果更佳哦&#xff0c;代码在最下面&#xff09;&#xff1a; QMessageBox手动添加有重试效果的按钮效果图&#xff1a; 点击详细文本之后展开如下图&#xff1a; 图标可选&#xff1a; QMessageBox::Critical错误图标QMessageBox::NoIco…...

【C++进阶】位图和布隆过滤器

文章目录位图位图概念位图使用场景位图的结构构造setresettest完整代码布隆过滤器布隆过滤器概念布隆过滤器结构构造setresettest完整版代码位图 位图概念 所谓位图&#xff0c;就是用每一位来存放某种状态&#xff0c;适用于海量数据&#xff0c;数据无重复的场景。通常是用…...

Android开发-Android UI与布局

01 Android UI 1.1 UI 用户界面(User Interface&#xff0c;简称 UI&#xff0c;亦称使用者界面)是系统和用户之间进行交互和信息交换的媒介&#xff0c;它实现信息的内部形式与人类可以接受形式之间的转换。软件设计可分为两个部分&#xff1a;编码设计与UI设计。 1.2 Andr…...

在不丢失数据的情况下解锁锁定的 Android 手机的 4 种方法

尽管您可以使用指纹解锁手机&#xff0c;但大多数智能手机都需要 PIN 码、图案或字母数字代码作为主密码。如果您有一段时间没有输入手机密码&#xff0c;很容易忘记。正是由于这个原因&#xff0c;即使您打开了指纹解锁&#xff0c;大多数智能手机也会让您每天至少输入一次 PI…...

【11】核心易中期刊推荐——人工智能 | 图形图像处理

🚀🚀🚀NEW!!!核心易中期刊推荐栏目来啦 ~ 📚🍀 核心期刊在国内的应用范围非常广,核心期刊发表论文是国内很多作者晋升的硬性要求,并且在国内属于顶尖论文发表,具有很高的学术价值。在中文核心目录体系中,权威代表有CSSCI、CSCD和北大核心。其中,中文期刊的数…...

Spring 中的事件发布与监听

主要代码在org.springframework.context&#xff0c;org.springframework.context.event包中 事件发布与监听主要包含以下角色&#xff1a; 事件&#xff1a;ApplicationEvent事件监听器&#xff1a;ApplicationListener SmartApplicationListener GenericApplicationListene…...

c++ 一些常识 2

前言 今天主要讲类相关概念。 构造和析构函数是否可以抛出异常 在构造函数中抛出异常&#xff0c;控制权会转出构造函数之外&#xff0c;对象的析构函数不会被调用&#xff0c;造成内存泄漏。 如果析构函数中抛出异常&#xff0c;而且没有在当地捕捉&#xff0c;析构函数便执…...

用嘴写代码?继ChatGPT和NewBing之后,微软又开始整活了,Github Copilot X!

用嘴写代码&#xff1f;继ChatGPT和NewBing之后&#xff0c;微软又开始整活了&#xff0c;Github Copilot X&#xff01; AI盛行的时代来临了&#xff0c;在这段时间&#xff0c;除了爆火的GPT3.5后&#xff0c;OpenAI发布了GPT4版本&#xff0c;同时微软也在Bing上开始加入了A…...

3分钟阐述这些年我的 接口自动化测试 职业生涯经验分享

接口自动化测试学习教程地址&#xff1a;https://www.bilibili.com/video/BV1914y1F7Bv/ 你好&#xff0c;我是凡哥。 很高兴能够分享我的接口自动化测试经验和心得体会。在我目前的职业生涯中&#xff0c;接口自动化测试是我经常进行的一项任务。通过不断地学习和实践&#xf…...

十大Python可视化工具,太强了

今天介绍Python当中十大可视化工具&#xff0c;每一个都独具特色&#xff0c;惊艳一方。 Matplotlib Matplotlib 是 Python 的一个绘图库&#xff0c;可以绘制出高质量的折线图、散点图、柱状图、条形图等等。它也是许多其他可视化库的基础。 import matplotlib.pyplot as p…...

五.ElasticSearch的基础+实战

五.ElasticSearch的基础+实战 1.Elasticsearch的是什么? 2.Elasticsearch的作用是什么? 3.Elasticsearch的核心思想? 4.Elasticsearch启动与简单使用 5.kibana结合elasticsearch实现简单的增删改查 6.elasticsearch安装中文分词器 7.elasticsearch结合springboot开发…...

Oracle的学习心得和知识总结(十三)|Oracle数据库Real Application Testing之Database Reply实操(一)

目录结构 注&#xff1a;提前言明 本文借鉴了以下博主、书籍或网站的内容&#xff0c;其列表如下&#xff1a; 1、参考书籍&#xff1a;《Oracle Database SQL Language Reference》 2、参考书籍&#xff1a;《PostgreSQL中文手册》 3、EDB Postgres Advanced Server User Guid…...

CAD外部参照如何重新定位?CAD外部参照重定位步骤

CAD外部参照如何重新定位&#xff1f;这个问题并不算是一个常见的问题&#xff0c;但偶尔也会遇到&#xff0c;今天小编就来给大家简单介绍一下浩辰CAD软件中CAD外部参照重定位的操作步骤&#xff0c;一起来看看吧&#xff01; CAD外部参照重定位步骤&#xff1a; 浩辰CAD软件…...

11. C#高级进阶

一、C# 异常处理 在 C# 中&#xff0c;异常是在程序运行出错时引发的&#xff0c;所有异常都派生自 System.Exception 类。异常处理就是处理运行时错误的过程&#xff0c;通过异常处理可以使程序在发生错误时保持正常运行。 C# 中的异常处理基于四个关键字构建&#xff0c;分别…...

网络编程套接字( TCP协议通讯流程)

目录 1、绑定失败问题 2、TCP协议通讯流程 三次握手的过程 数据传输的过程 四次挥手的过程 TCP和UDP对比 1、绑定失败问题 当我们测试网络代码时&#xff0c;先将服务端绑定8080端口运行&#xff0c;然后运行客户端&#xff0c;并让客户端连接当前服务器&#xff1a; 当有客户…...

WPF毛笔字实现过程

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…...

MHA实现mysql数据库高可用

目录 MHA原理 MHA工具包 MHA实现mysql高可用实战 MHA原理 ①MHA利用 SELECT 1 As Value 指令判断master服务器的健康性,一旦master 宕机,MHA 从宕机崩溃的master保存二进制日志事件&#xff08;binlog events&#xff09; ②识别含有最新更新的slave ③应用差异的中继日志&…...

leetcode每日一题:55. 跳跃游戏

系列&#xff1a;贪心算法 语言&#xff1a;java 题目来源&#xff1a;Leetcode55. 跳跃游戏 题目 给定一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。 数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标。 示例 1: 输…...

【C++】map 和 set

文章目录一、关联式容器与键值对1、关联式容器2、键值对 pair3、树形结构的关联式容器二、set1、set 的介绍2、set 的使用三、multiset四、map1、map 的介绍2、map 的使用五、multimap一、关联式容器与键值对 1、关联式容器 在C初阶的时候&#xff0c;我们已经接触了 STL 中的…...

基于SpringBoot的酒店管理系统

系统环境 开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/i…...

JAVA框架知识整理

框架知识整理 SpringBoot、SpringMVC、Spring的区别和他们的作用&#xff1f; SpringBoot是一个微服务框架&#xff0c;其简化了Spring应用的创建、运行、测试、部署。使开发人员无需过多的关注XML配置。里面整合了许多框架例如SpringMVC、Spring Security和Spring Data JPA。…...

运算放大器:电压比较器

目录一、单限电压比较器二、滞回电压比较器三、窗口电压比较器最近在学习电机控制&#xff0c;遇到了与运算放大电路相关的知识&#xff0c;然而太久没有接触模拟电路&#xff0c;对该知识已经淡忘了&#xff0c;及时温故而知新&#xff0c;做好笔记&#xff0c;若有错误、不足…...

Linux的基础知识

根目录和家目录根目录&#xff1a;是Linux中最底层的目录&#xff0c;用"/"表示家目录&#xff1a;当前用户所在的路径&#xff0c;用“~”表示&#xff0c;root用户的家目录和普通用户的家目录不一样&#xff0c;普通用户的家目录在/home路径下&#xff0c;每一个用…...

【JavaEE】 IntelliJ IDEA 2022.2最新版Tomcat导入依赖详细教程全解及创建第一个Servlet程序

目录 一、软件资源 二、放置settings.xml文件 三、创建项目 四、引入依赖 ​五、创建目录 六、编写代码 写在前面&#xff1a;☞What is Servlet? Servlet其实是一种实现动态页面的技术。是一组由Tomcat提供给程序员的API&#xff08;应用程序编程接口&#xff09;…...

常见的卷积神经网络结构——分类、检测和分割

本文持续更新~~ 本文整理了近些年来常见的卷积神经网络结构&#xff0c;涵盖了计算机视觉领域的几大基本任务&#xff1a;分类任务、检测任务和分割任务。对于较复杂的网络&#xff0c;本文只会记录其中的核心模块以及重要的网络设计思想&#xff0c;并不会记录完整的网络结构。…...

企业网站制作报价表/东莞网站营销

python机器学习库sklearn之支持向量机svm介绍python数据挖掘系列教程这里只讲述sklearn中如何使用svm算法进行分类sklearn.svm模块提供了很多模型供我们使用&#xff0c;本文使用的是svm.SVC&#xff0c;它是基于libsvm实现的。参数说明如下&#xff1a;C&#xff1a;惩罚项&am…...

网络服务协议模板/搜索引擎优化包括哪些方面

--完整备份 BACKUP DATABASE JINWEI TO DISKD:\BAK\JINWEIFULL.bak--日志备份 BACKUP LOG JINWEI TO DISKD:\BAK\JINWEILOG.bak--差异备份 BACKUP DATABASE JINWEI TO DISKD:\BAK\JINWEIDIFF.bak WITH DIFFERENTIAL--备份数据库并压缩   backup database 数据库名称 to disk备…...

武汉专业建站网/推广恶意点击软件怎样使用

假设有aViewController bViewController&#xff0c;如何判断当前View是哪个ViewController激活呢&#xff1f;我们使用如下的方法即可简单实现。 if([viewController isMemberOfClass:NSClassFromString("aViewController")]){//do something}if([viewController …...

浙江建设厅网站那三类人员/网站优化是什么意思

直接修改 /etc/inittab文件 改这一行 id:5:initdefault: 其中的5就是指runlevle的图形模式 3是命令行模式 其他分别是&#xff1a; 0 系统停机 1 单用户模式 2 多用户模式 3 网络多用户模式 4 保留 5 X11模式&#xff08;即进入图形界面模式&#xff0…...

专业的河南网站建设公司/搜狗站长管理平台

Hive 常用函数备忘 1.转换函数 cast (value as type) , 显式的将一个类型的数据转化为另一种类型的数据, 若不能进行转化则返回 null 值. select cast(salary as char(1));返回一个char类型的salary, 若不能进行转化则返回null值.2.条件判断函数 case [...] when ... then …...

如何把地图放到自己做的网站上/百度推广登录地址

转载于:https://www.cnblogs.com/lianghong881018/p/10761990.html...