多线程知识点

news2025/7/12 8:06:55

多线程

基本知识

创建线程的常用三种方式:

  1. 继承Thread类
  2. 实现Runnable接口
  3. 实现Callable接口(JDK1.5>=)
public class ThreadTest extends Thread {
  @Override
  public void run() {
    System.out.println(this.getName() + "..开始..");
    int i = 0;
    // 中断标志位结束
    while (!Thread.interrupted()) {
      i++;
    }
    System.out.println(this.getName() + "..结束.." + i);
  }
}
public class RunnableTest implements Runnable {
  @Override
  public void run() {
    System.out.println(" RunnableTest");
  }
}
public class CallableTest implements Callable<String> {
  @Override
  public String call(){
    System.out.println("CallableTest");
    return "2CallableTest";
  }
}
//睡眠  Thread.sleep(2000);
//加入到主线程   	t1.join();
  	Thread t1 = new Thread(new ThreadTest());
  	t1.start(); 
  	t1.join();
	Thread t2 = new Thread(new RunnableTest());
	t2.start();
  	FutureTask t3 = new FutureTask(new CallableTest());
 	t3.run();
	//获取返回值
	String a = t3.get();	
	//中断标志位,若这里不中断,则在while循环中一直进行
	t1.interrupt();		

在大量数据时,设置优先级

 t3.setPriority (6);
//最大优先级 十级 默认为五级 优先级 

生命周期是那些?

在这里插入图片描述

主线是:新建–>可运行状态–>运行–>终止状态

运行时,会有三种阻塞:

  1. 其他阻塞:sleep()睡眠,等待时间到 ; join()合并线程,从并行到串行,
  2. 对象锁阻塞:synchronized:同步锁,获得锁
  3. 等待阻塞:wait();

sleep和wait区别?

sleep()方法是Thread类里面的,主要的意义就是让当前线程停止执行,让出cpu给其他的线程,但是不会释放对象锁资源以及监控的状态,当指定的时间到了之后又会自动恢复运行状态。

wait()方法是Object类里面的,让线程放弃当前的对象的锁,进入等待此对象的等待锁定池,只有针对此对象调动notify方法后本线程才能够进入对象锁定池准备获取对象锁进入运行状态

为啥wait,notify,notifyAll不在thread类中?

wait()和notfity()必须在同步代码块里

对象级别,而不是线程级别!

notify和ntityAll区别: 唤醒一个,和唤醒全部

synchronized 和(Lock锁) ReentrantLock区别?

  1. 相似点:

    加锁方式同步,都是阻塞式的同步:意思是说,A线程获得了锁进入代码块,其他的BCD全外面等着

  2. 区别:

    synchronized 是关键字,lock()和unlock()成对出现.

    synchronized 非公平锁, lock()默认非公平锁,可以设置为公平锁.性能一般

线程安全讲一下,有哪几种?

原子,可见,有序

线程安全就是,访问一段代码,产生的确定的结果!

多线程,单线程,执行下永远一致,那么就是线程安全.

  1. 不可变:

    例:String,Integer,Long,这些final类型,任何一个线程都无法改变,除非新创建.

  2. 绝对线程安全:

    不管运行时环境如何,不需要额外的同步措施,

  3. 相对线程安全:

    通常意义上的线程安全,如Vector,Concurrent HashMap,add,remove操作等,不会被打断

  4. 线程非安全:

    例如:ArrayList,LinedList,HashMap等

问:ArrayList线程安全吗?

​ 答:不安全,可用 Vector,synchronizedList 或 加锁

问:HashMap线程安全吗?

​ 答:不安全,可用Hashtable、synchronizedMap、ConcurrentHashMap。

线程池7参数:

  1. corePoolSize:线程池中的常驻核心线程数
  2. maximumPoolSize:线程池能够容纳同时执行的最大线程数
  3. keepAliveTime:多余的空闲线程的存活时间
  4. unit:存活时间单位
  5. workQueue:任务队列,被提交但尚未被执行的任务。
  6. threadFactory: 表示生成线程池中工作线程的线程工厂
  7. handIer:拒绝策略

线程池流程

在这里插入图片描述

4拒绝策略:

  1. AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
  2. DiscardPolicy:丢弃任务,但是不抛出异常。
  3. DiscardOldestPolicy:丢弃队列最久的任务,然后重新提交被拒绝的任务
  4. CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务

线程安全要保证,原子性,可见性,有序性

原子性:同步机制,加锁实现

可见性:volatile保证可见性

有序性:按照顺序执行

线程之间如何通信?

共享内存

在这里插入图片描述

同步?异步?阻塞?非阻塞?是啥?

客户端发送请求时

同步:客户端发送请求时,等待方法调用执行完,

异步:客户端发送请求时,不用等上一个方法调用完

阻塞,非阻塞,是服务端的处理,

阻塞:处理A时,其他BCD都需要等

非阻塞:可以处理其他的.

四个概念:

  1. BIO同步阻塞:效率不好,等全部完成,返回; 其他都给我等着
  2. NIO同步非阻塞:可以先处理其他的,
  3. 异步阻塞:不等,先做其他的,处理完 ,类似 ajxa
  4. AIO异步非阻塞:不等,处理其他请求.高效

IO流简单说下?

image-20230218145229610

啥是锁?分为几类?

通俗易懂 悲观锁、乐观锁、可重入锁、自旋锁、偏向锁、轻量/重量级锁、读写锁、各种锁及其Java实现_依丨稀的博客-CSDN博客

  1. 乐观锁?悲观锁?
  2. 偏向锁?->轻量级锁?(自旋锁?)->重量级锁?
  3. 升锁(锁膨胀)?降锁?锁竞争?
  4. 可重入锁(递归锁)?
  5. 公平锁?非公平锁?
  6. 可中断锁?

读写锁其实是一对锁,一个读锁(共享锁)和一个写锁(互斥锁、排他锁)。

降锁:只有在垃圾回收的时候才会降,可以理解为不可及降

原子性问题?

线程安全?

问:为啥会出现这种问题?

答:多线程操作共享数据导致的

锁:

  • 悲观锁:synchronization , lock(AQS)

  • 乐观锁:CAS(比较与交换,Compare and swap)

让每个线程玩自己的数据,互不打扰,ThreadLocal

  1. 加锁synchronized,保证同一时间只有一个线程操作变量,其他线程需等待操作结束才能使用临界资源
  2. 使用CAS操作,变量计算前保留一份旧值a,计算完成后结果值为b,把b刷到内存之前先比较a是否和内存中变量一致,如果一致,就把内存中的变量赋值为b,不一样,重新获取内存中变量值,重复一遍操作,一直到a和内存中一致,操作结束。

CAS底层实现?比较与交换 Compare-and-Swap

啥是CAS?

啥是CAS? 就是 比较与交换

先比较是否与预期值一致,

  • 一致,交换,返回 ture;

  • 不一致,拒绝,返回 false;

在java api方面可以看到,

//哪个对象?哪个属性的内存偏移量?oldValue,newValue
compareAndAwapObject(Object var1,long var2,Object var4,Object var4);

compareAndAwapInt(Object var1,long var2,Object var4,Object var4);

compareAndAwapLong(Object var1,long var2,Object var4,Object var4);

Java中真正的CAS操作调用的native方法,再往下就是C++内容。再往下就是汇编语言,cpu硬件底层支持比较与交换,若是多核,加lock,cpu层面的锁保证原子性.

因为整个过程中并没有“加锁”和“解锁”操作,因此乐观锁策略也被称为无锁编程。换句话说,乐观锁其实不是“锁”,它仅仅是一个循环重试CAS的算法而已!

ABA:

ABA不一定是问题,只是++,–的操作,不存在问题

线程A:A1->B2

线程B:B2->A3

线程C:A1->C4

java已经提供了,在修改value的同时,指定版号

自旋次数过多:

自旋次数多,会造成占用大量的CPU资源.

synchronization方向:从CAS几次失败后,会挂起(WAITING),避免占用资源

longAdder方向:基于分段锁的形式解决(看业务)

只针对一个属性保证原子性:

ReentrantLook基于AQS,AQS基于CAS.

四种引用类型+ThreadLocal的问题:

问:为什么要说四种引用和ThreadLocal的关系呢?

答:在ThreadLocal中,有个ThreadLocalMap,其中有entry有key-value

其中key是弱引用,value是强引用

为了区分,所以要提及四种引用

问:既然key是弱引用,那么为什么还会造成内存泄露?如何解决?

答:value是强引用,虽然key弱引用gc会回收,但是value不会回收。导致泄露,

答:用完以后 thread.remove();即可

四种引用类型:

引用:User xx=new User(); xx就是强引用,只要引用还在,就不会回收.

引用:单独用一个SofeReference引用的对象,就是软引用,如果内存不足,只有软引用回收

SofeReference xx=new SofeReference(new User);//软引用
User user=xx.get();//强引用
//因存在强引用,无法被回收;;引用只有软引用,才会被回收

引用:WeakReference引用的对象,一般就是弱引用,只要执行GC,就会回收只有弱引用的对象.可以解决内存泄露的问题,看ThreadLocal即可.

引用:PhantomReference引用的对象,就是虚引用,拿不到虚引用指向的对象,**一般监听GC回收阶段,或者是回收堆外内存时使用。**虚引用只是用来监视对象的回收。

可见性问题?

JAVA内存模型

(JVM内存模型和Java模型不是一个东西)

在这里插入图片描述

CPU从缓存拉数据,缓存有三级,L1,L2,L3,都没有则去主内存拉取,JMM就是CPU和主内存之间,协调。保证可见,有序等

缓存是CPU的缓存,CPU的缓存分为L1(线程独享),L2(内核独享),L3(多核共享)

JMM就是Java内存模型的核心,可见性,有序性都基于这实现。

主内存JVM,就是你堆内存。

jvm内存模型

在这里插入图片描述

有什么可以保证 可见性 ?

啥是可见性?

线程之间,对变量的变化是否可见

java层面:(可见:记录问题,可见性测试)

  • volatile:保证cpu每次操作数据,都是主内存读写
  • synchronization:保证前面操作的数据是可见的。
  • lock:也可以保证CAS或者操作volatile的变量之后,可以保证前面操作的数据是可见的。
  • final:是常量没法动

volatile修饰引用数据类型

首先volatile 修饰引用数据类型,只能保证引用数据类型的地址是可见的,不保证内部数据可见

注意:hotspot中实现,若换一个版本则效果不同,只用于面试,不能这么干活!

public class ConpanyTest {
  static class A {
    boolean b = true;
    //volatile boolean b = true; 加这里,保证了b的可见性,这里会(结束)
    void run() {
      while (b) {}
      System.out.println("结束");
    }
  }

  static  A a = new A();
  //static volatile A a = new A(); 加这里,不保证内部数据可见.所以还是死循环
  public static void main(String[] args) throws InterruptedException {
    new Thread(a::run).start();
    // new Thread(() -> a.run()).start();
    Thread.sleep(10);
    a.b = false;
  }
}

有了MESI协议,为啥还有volatile?

MESI协议:硬件协议

volatile:软件的java中JMM的一致性

volatile的可见性底层 如何实现的?

volatile的底层生产的汇编lock指令,之歌指令会要求强行写入主内存,并且可以忽略Store Buffer这种缓存,从而达到可见性的目的,而且会利用MESI协议,让其他缓存失效.

有序性高频问题:

什么是有序性?

单例模式,懒汉机制.

懒汉为保证现场安全,会采用DCL方法,

但是,单用DCL,依然有几率出现问题.空指针

在Java编译.java为.class时,会基于 即时编译(JIT)做优化,将指令的顺序做调整,提升执行效率

在CPU层次,也会对一些执行进行重新排序,从而提升执行效率.

解决方案:加锁(还是加锁)synchronized和Lock,保证同一时刻只有一个线程进行操作

使用volatile修饰变量,在JMM中volatile的读和写都会插入内存屏障来禁止处理器的重排

volatile的有序性底层实现?

被volatile修饰的属性,在编译时,会在前后追加内存屏障

  • SS:屏障前读写操作,必须全部完成,再执行后续操作
  • SL:屏障前写操作,必须全部完成,再执行读操作
  • LL:屏障前读操作,必须全部完成,再执行后续读操作
  • LS:屏障前读操作,必须全部完成,再执行后续写操作
  • 在这里插入图片描述

内存屏障在JDK规定的,目的是保证volatile修饰的属性不会出现指令重排的问题.

synchronization 问题?

synchronization 锁升级过程?

锁就是对象,随便哪一个都可以,Java中所有对象都是锁。

无锁(匿名偏向)、偏向锁、轻量级锁、重量级锁

无锁(匿名偏向): 一般情况下,new出来的一个对象,是无锁状态。因为偏向锁有延迟,在启动JVM的4s中,不存在偏向锁,但是如果关闭了偏向锁延迟的设置,new出来的对象,就是匿名偏向。

偏向锁: 当某一个线程来获取这个锁资源时,此时,就会变为偏向锁,偏向锁存储线程的ID

当偏向锁升级时,会触发偏向锁撤销,偏向锁撤销需要等到一个安全点,比如GC的时候,偏向锁撤销的成本太高,所以默认开始时,会做偏向锁延迟。

安全点:

  • GC
  • 方法返回之前
  • 调用某个方法之后
  • 甩异常的位置
  • 循环的末尾

轻量级锁: 当在出现了多个线程的竞争,就要升级为轻量级锁(有可能直接从无锁变为轻量级锁,也有可能从偏向锁升级为轻量级锁),轻量级锁的效果就是基于CAS尝试获取锁资源,这里会用到自适应自旋锁,根据上次CAS成功与否,决定这次自旋多少次。

重量级锁: 如果到了重量级锁,那就没啥说的了,如果有线程持有锁,其他竞争的,就挂起。

synchronized锁粗化&锁消除?

锁粗化(锁膨胀):(JIT优化)

while(){
   sync(){
      // 多次的获取和释放,成本太高,优化为下面这种
   }
}
//----
sync(){
   while(){
       //  优化成这样
   }
}

锁消除:在一个sync中,没有任何共享资源,也不存在锁竞争的情况,JIT编译时,就直接将锁的指令优化掉。

4.3 synchronized实现互斥性的原理?

偏向锁:查看对象头中的MarkWord里的线程ID,是否是当前线程,如果不是,就CAS尝试改,如果是,就拿到了锁资源。

轻量级锁:查看对象头中的MarkWord里的Lock Record指针指向的是否是当前线程的虚拟机栈,如果是,拿锁执行业务,如果不是CAS,尝试修改,修改他几次,不成,再升级到重量级锁。

重量级锁:查看对象头中的MarkWord里的指向的ObjectMonitor,查看owner是否是当前线程,如果不是,扔到ObjectMonitor里的EntryList中,排队,并挂起线程,等待被唤醒。

在这里插入图片描述

4.4 wait为什么是Object下的方法?

执行wait方法需要持有sync锁。

sync锁可以是任意对象。

同时执行wait方法是在持有sync锁的时候,释放锁资源。

其次wait方法需要去操作ObjectMonitor,而操作ObjectMonitor就必须要在持有锁资源的前提的才能操作,将当前线程扔到WaitSet等待池中。

同理,notify方法需要将WaitSet等待池中线程扔到EntryList,如果不拥有ObjectMonitor,怎么操作!

类锁就是基于类.class作为 类锁

对象锁,就是new 一个对象作为 对象锁

设计模式(单例,工厂,代理,消费者生产者,策略,责任链,观察者,模板,装饰者),多线程,JVM,MySQL,Spring,SpringBoot,Redis,MQ

1

记录问题

多线程demo

存在两个问题,需要注意

public class Demo {
  public static void main(String[] args) {

    Ticket target = new Ticket();
    for (int i = 0; i < 10; i++) {
      Thread t1 = new Thread(new Ticket(), "售票" + i);
      // Thread t1 = new Thread(target, "售票" + i);
      //这里可以用(new Ticket(), "售票" + i);是因为 下面加了static
      t1.start();
    }
  }
}

class Ticket implements Runnable {
  private static int ticket = 100;
  //static,全局变量
  @Override
  //public synchronized void run() {
  //synchronized 加到方法上时候,并不能生效,对象锁,锁住了方法,没有锁住代码块
  public void run() {
    while (true) {
      synchronized ("z") {
        try {
          Thread.sleep(10);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
        if (ticket > 0) {
          String name = Thread.currentThread().getName();
          System.out.println(name + "正在卖:" + ticket--);
        } else {
          System.out.println(Thread.currentThread().getName() + "售罄!!!");
          break;
        }
      }
    }
  }
}

volatile 可见性测试

/** volatile 可见性测试--- volatile */
  // static 只是说明这个变量为该类的所有实例所共有,但是线程访问该变量时还是从主内存拷贝一份回工作内存,至于什么时候同步回主内存那就不好说了。
  //volatile 表示即使你从主内存拷贝到了工作内存,你每次要用的时候还是要去主内存同步,如果变量发生了改变就拿最新的,如果当前线程改变了这个变量也要写回到主内存。
/** volatile 可见性测试 */
public class VolatileTest {
  static volatile boolean flag = true; // 用volatile修饰

  public static void main(String[] args) throws InterruptedException {
    new Thread(
            () -> {
              while (flag) {}
              System.out.println("t1结束!");
            })
        .start();
    Thread.sleep(100);
    flag = false;
  }
}
///
/** volatile 可见性测试 ---synchronized */
public class VolatileTest {

  static boolean flag = true; // 不用volatile修饰

  public static void main(String[] args) throws InterruptedException {
    new Thread(
            () -> {
              while (flag) {
                synchronized (VolatileTest.class) {
                }
              }
              System.out.println("t1结束!");
            })
        .start();
    Thread.sleep(100);
    flag = false;
  }
}

/** volatile 可见性测试---lock */
public class VolatileTest {

  static boolean flag = true; // 不用volatile修饰
  static ReentrantLock lock = new ReentrantLock();

  public static void main(String[] args) throws InterruptedException {
    new Thread(
            () -> {
              while (flag) {
                lock.lock();
                lock.unlock();
              }
              System.out.println("t1结束!");
            })
        .start();
    Thread.sleep(100);
    flag = false;
  }
}

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

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

相关文章

国内动漫绘画培训班盘点

动漫培训机构哪家好&#xff1f;动漫培训班是一种有效的提升动漫水平的方式&#xff0c;可以帮助学生提高绘画技巧和技能&#xff0c;更好地表达自己的艺术想法。 一&#xff1a;动漫培训班排名 1、轻微课&#xff08;五颗星&#xff09; 主打课程有日系插画、游戏原画、古风插…

C语言进阶(二)—— 指针强化

1. 指针是一种数据类型1.1 指针变量指针是一种数据类型&#xff0c;占用内存空间&#xff0c;用来保存内存地址。void test01(){int* p1 0x1234;int*** p2 0x1111;printf("p1 size:%d\n",sizeof(p1));printf("p2 size:%d\n",sizeof(p2));//指针是变量&am…

Python实现贝叶斯优化器(Bayes_opt)优化卷积神经网络分类模型(CNN分类算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。1.项目背景贝叶斯优化器(BayesianOptimization) 是一种黑盒子优化器&#xff0c;用来寻找最优参数。贝叶斯优化器是基…

Redis+Caffeine多级(二级)缓存,让访问速度纵享丝滑

目录多级缓存的引入多级缓存的优势CaffeineRedis实现多级缓存V1.0版本V2.0版本V3.0版本多级缓存的引入 在高性能的服务架构设计中&#xff0c;缓存是一个不可或缺的环节。在实际的项目中&#xff0c;我们通常会将一些热点数据存储到Redis或MemCache这类缓存中间件中&#xff0…

【100个 Unity实用技能】☀️ | Unity 通过自定义菜单将资源一键导出

Unity 小科普 老规矩&#xff0c;先介绍一下 Unity 的科普小知识&#xff1a; Unity是 实时3D互动内容创作和运营平台 。包括游戏开发、美术、建筑、汽车设计、影视在内的所有创作者&#xff0c;借助 Unity 将创意变成现实。Unity 平台提供一整套完善的软件解决方案&#xff…

ESP32设备驱动-内置电容触摸传感器

内置电容触摸传感器 文章目录 内置电容触摸传感器1、电容触摸传感器介绍2、软件准备3、硬件准备4、代码实现本文将详细介绍如何使用ESP32的内置电容式传感器。 1、电容触摸传感器介绍 ESP32 具有可用作触摸按钮的电容式传感器。 这些是引脚排列上著名的TOUCH引脚。 在开发板的…

vs2019+opencv450+opencv contrib450+cmake3.25.2安装流程

目的 为了研究利用sift、orb、surf等算法进行视觉特征检测&#xff0c;第一次配置折腾了四五天。 电脑环境 win10 opencv4.5.0 opencv contrib 4.5.0 cmake3.25.2 报错 问题1 OpenCV(3.4.3) Error: The function/feature is not implemented (This algorithm is patented…

基于QUIC 协议的HTTP/3

HTTP/2 存在一些比较严重的与 TCP 协议相关的缺陷&#xff0c;但由于 TCP 协议僵化&#xff0c;我们几乎不可能通过修改 TCP 协议自身来解决这些问题&#xff0c;那么解决问题的思路是绕过 TCP 协议&#xff0c;发明一个 TCP 和 UDP 之外的新的传输协议。但是这也面临着和修改 …

Dart 表达式以及语法糖汇总

前言 Dart语言中有许多语法糖或者说lambda表达式&#xff0c;语法和代码量是简洁了许多&#xff0c;但给想要入门的我添加了许多困扰&#xff0c;我经常看官方API或者第三方文档API的时候&#xff0c;在示例中大量的使用了类似的语法糖&#xff0c;让代码的可读性大大下降&…

内部知识管理应该怎么做?

许多公司都知道需要有一个面向客户的知识库&#xff0c;以加强客户服务&#xff0c;提供更好的客户体验。 但是很多企业没有意识到的是&#xff0c;拥有一个内部知识库软件对于员工改善沟通和促进知识共享的重要性。 协作是组织成功的关键部分&#xff0c;通过明确的远景和使命…

微服务之Ribbon负载均衡

&#x1f3e0;个人主页&#xff1a;阿杰的博客 &#x1f4aa;个人简介&#xff1a;大家好&#xff0c;我是阿杰&#xff0c;一个正在努力让自己变得更好的男人&#x1f468; 目前状况&#x1f389;&#xff1a;24届毕业生&#xff0c;奋斗在找实习的路上&#x1f31f; &#x1…

论文笔记:DropMessage: Unifying Random Dropping for Graph Neural Networks

&#xff08;AAAI 23 优秀论文&#xff09; 1 intro GNN的一个普遍思路是&#xff0c;每一层卷积层中&#xff0c;从邻居处聚合信息 尽管GNN有显著的进步&#xff0c;但是在大规模图中训练GNN会遇到各种问题&#xff1a; 过拟合 过拟合之后&#xff0c;GNN的泛化能力就被限制…

Matplotlib精品学习笔记001-图形绘制常见的组分有哪些?

简介 从头学习&#xff0c;逐步精美 学习蓝本 学习资料是Quick start 内容 所有绘图的起始步骤 import matplotlib as mpl import matplotlib.pyplot as plt import numpy as np通过一个简单的例子认识Matplotlib绘图的过程&#xff0c;见代码注释 import matplotlib.py…

重温Python基础知识点,又来重新巩固一遍

前言 最近有很多朋友刚接触python学的还是有点模糊 还有的朋友就是想重温一下基础内容&#xff0c;毕竟基础不牢地动山摇 行吧&#xff0c;就总结了以下的一些知识点&#xff0c;可以都看看哈 一、开发环境搭建 更多学习资料.点击领取即可 1.1 Python解释器的安装 Python解…

ctfshow 代码审计专题

文章目录web 301web 302web 303web 304web 305web 306web 307web 308web 309web 310web 301 简单看一下&#xff0c;在checklogin.php中发现了sql语句&#xff0c;且没过滤&#xff0c;直接sql注入。 –form测试,–batch绕过waf.–dump列出所有库和表。 得到账号密码&#xf…

MySQL数据库————MVCC

MySQL的脏读、幻读、不可重复读 脏读 现在有两个事务在操作table表&#xff0c;事务B修改了id2的name字段为李老四&#xff0c;但是没有提交&#xff0c;事务A查询id2的数据&#xff0c;得到name为李老四&#xff1b;事务B发生回滚&#xff0c;id2的数据的name又变回李四&…

Linux 防火墙配置(iptables和firewalld)

目录 防火墙基本概念 Iptables讲解 Iptables表 Iptables规则链 Iptables控制类型 Iptables命令配置 firewalld讲解 Firewalld区域概念 Firewalld两种配置方法 firewall-cmd命令行基础配置 firewall-config图形化配置 防火墙基本概念 防火墙就是根据系统管理员设定的…

用 tensorflow.js 做了一个动漫分类的功能(二)

前言&#xff1a;前面已经通过采集拿到了图片&#xff0c;并且也手动对图片做了标注。接下来就要通过 Tensorflow.js 基于 mobileNet 训练模型&#xff0c;最后就可以实现在采集中对图片进行自动分类了。这种功能在应用场景里就比较多了&#xff0c;比如图标素材站点&#xff0…

java集成redis简单存储

这里主要将数据存redis并设置过期时间、通过key删除redis、通过key更新redis&#xff08;续期&#xff09; 将数据存redis并设置过期时间 引入redis依赖 import org.springframework.data.redis.core.StringRedisTemplate;AutowiredStringRedisTemplate stringRedisTemplate…

【基础教程】Appium自动化测试,太详细了!

Appium简介Appium是一款开源的Appium自动化工具, 基于Webdriver协议, 主要有以下3个特点:全能: 支持iOS/Andorid/H5/混合App/WinApp通用: 支持Win/Linux/Mac, 支持Java/Python/Ruby/Js/PHP等各种语言开源: 免费App自动化测试工具对比iOS官方:Uiautomation/XCUITest: 白盒, UI测…