java多线程编程面试题总结

news2024/9/27 9:18:52

一些最基本的基础知识就不总结了,参考之前写的如下几篇博客,阅读顺序从上到下,依次递进。

java 多线程 多线程概述及其三种创建方式 线程的常用方法

java 线程安全问题 三种线程同步方案 线程通信(了解)

java 线程池 并发并行 线程的生命周期

java 多线程乐观锁与悲观锁

目录

  • 基础知识补充
    • 新建 T1、T2、T3 三个线程,如何保证它们按顺序执行?
    • 在 java 中 wait 和 sleep 方法的不同?
    • 如何停止一个正在运行的线程?
  • 线程中并发锁知识补充
    • synchronized关键字的底层原理
    • 谈谈 JMM(Java 内存模型)
    • CAS
    • volatile
    • AQS
    • ReentrantLock的实现原理
    • synchronized和Lock有什么区别 ?
    • 死锁产生的条件是什么?如何避免死锁?如何如何进行死锁诊断?
    • ConcurrentHashMap
    • 并发程序出现问题的根本原因(并发三大特性)
  • ThreadLocal详解
    • ThreadLocal-内存泄露问题

基础知识补充


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

可以用线程类的join()方法在一个线程中启动另一个线程,另外一个线程完成该线程继续执行。

为了确保三个线程的顺序你应该先启动最后一个(T3调用T2,T2调用T1),这样T1就会先完成而T3最后完成

public class JoinTest {

    public static void main(String[] args) {

        // 创建线程对象
        Thread t1 = new Thread(() -> {
            System.out.println("t1");
        }) ;

        Thread t2 = new Thread(() -> {
            try {
                t1.join();                          // 加入线程t1,只有t1线程执行完毕以后,再次执行该线程
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("t2");
        }) ;


        Thread t3 = new Thread(() -> {
            try {
                t2.join();                              // 加入线程t2,只有t2线程执行完毕以后,再次执行该线程
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("t3");
        }) ;

        // 启动线程
        t1.start();
        t2.start();
        t3.start();

    }

}


在 java 中 wait 和 sleep 方法的不同?

共同点

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

不同点

  • 方法归属不同,sleep(long) 是 Thread 的静态方法,而 wait(),wait(long) 都是 Object 的成员方法,每个对象都有
  • 醒来时机不同,首先它们都可以被interrupt()方法打断唤醒执行。正常情况sleep(long) 和 wait(long) 的线程都会在等待相应毫秒后醒来,wait(long) 和 wait() 还可以被 notify 唤醒,wait() 如果不唤醒就一直等下去。
  • 锁特性不同(重点)
    • wait 方法的调用必须先获取 wait 对象的锁,而 sleep 则无此限制
    • wait 方法执行后会释放对象锁,允许其它线程获得该对象锁(我放弃cpu,但你们还可以用)
    • 而 sleep 如果在 synchronized 代码块中执行,并不会释放对象锁(我放弃cpu,你们也用不了)


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

有三种方式可以停止线程

  • 当run方法完成后线程终止
  • 使用stop方法强行终止(不推荐,方法已作废)
  • 使用interrupt方法中断线程

其中stop方法就是下面这样使用:

MyInterrupt2 t1 = new MyInterrupt2() ;
t1.start();
// 主线程休眠2秒
Thread.sleep(6000);
// 调用stop方法
t1.stop();

注意调用interrupt()方法并不会立即停止线程,它只是改变了线程的中断状态,具体是否能够停止线程,还需要看这个线程的具体代码实现。如果线程中没有处理中断的逻辑,那么即使调用了interrupt()方法,线程也不会停止。因此,编写多线程代码时,我们需要特别注意线程的中断处理。这就是"打断唤醒"的基本含义。

package com.itheima.basic;

public class MyInterrupt3 {

    public static void main(String[] args) throws InterruptedException {

        //2.打断正常的线程
        Thread t2 = new Thread(()->{
            while(true) {
                Thread current = Thread.currentThread();
                boolean interrupted = current.isInterrupted();
                if(interrupted) {
                    System.out.println("打断状态:"+interrupted);
                    break;
                }
            }
        }, "t2");
        t2.start();
        Thread.sleep(500);
//        t2.interrupt();

    }
}


线程中并发锁知识补充

synchronized关键字的底层原理

参考回答:

  • Synchronized【对象锁】采用互斥的方式让同一时刻至多只有一个线程能持有【对象锁】
  • 它的底层由monitor实现的,monitor是jvm级别的对象( C++实现),线程获得锁需要使用对象(锁)关联monitor
  • 在monitor内部有三个属性,分别是owner、entrylist、waitset
  • 其中owner是关联的获得锁的线程,并且只能关联一个线程;entrylist关联的是处于阻塞状态的线程;waitset关联的是处于Waiting状态的线程


谈谈 JMM(Java 内存模型)

JMM(Java Memory Model)Java内存模型,是java虚拟机规范中所定义的一种内存模型。
Java内存模型(Java Memory Model)描述了Java程序中各种变量(线程共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取变量这样的底层细节。

在这里插入图片描述

特点:

  • 所有的共享变量都存储于主内存(计算机的RAM)这里所说的变量指的是实例变量和类变量。不包含局部变量,因为局部变量是线程私有的,因此不存在竞争问题。
  • 每一个线程还存在自己的工作内存,线程的工作内存,保留了被线程使用的变量的工作副本。
  • 线程对变量的所有的操作(读,写)都必须在工作内存中完成,而不能直接读写主内存中的变量,不同线程之间也不能直接访问对方工作内存中的变量,线程间变量的值的传递需要通过主内存完成。


CAS

CAS的全称是: Compare And Swap(比较再交换),它体现的一种乐观锁的思想,在无锁情况下保证线程操作共享数据的原子性。
在JUC( java.util.concurrent )包下实现的很多类都用到了CAS操作

  • AbstractQueuedSynchronizer(AQS框架)
  • AtomicXXX类

基于刚才学习过的JMM内存模型进行说明

线程1与线程2都从主内存中获取变量int a = 100,同时放到各个线程的工作内存中

在这里插入图片描述

一个当前内存值V、旧的预期值A、即将更新的值B,当且仅当旧的预期值A和内存值V相同时,将内存值修改为B并返回true,否则什么都不做,并返回false。如果CAS操作失败,通过自旋的方式等待并再次尝试,直到成功

在这里插入图片描述



volatile

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

保证线程间的可见性

保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的
值,这新值对其他线程来说是立即可见的,volatile关键字会强制将修改的值立即
写入主存。

禁止进行指令重排序

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


下面解释一下这两个含义,首先是保证线程间的可见性,如下案例所示

package com.itheima.basic;


// 可见性例子
// -Xint
public class ForeverLoop {
    static boolean stop = false;

    public static void main(String[] args) {
        new Thread(() -> {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            stop = true;
            System.out.println("modify stop to true...");
        }).start();
        foo();
    }

    static void foo() {
        int i = 0;
        while (!stop) {
            i++;
        }
        System.out.println("stopped... c:"+ i);
    }
}

当执行上述代码的时候,发现foo()方法中的循环是结束不了的,也就说读取不到
共享变量的值结束循环。主要是因为在JVM虚拟机中有一个JIT(即时编辑器)给代码做了优化。在很短的时间内,foo中while循环执行的次数太多了,当达到了一个阈值,JIT就会优化此代码,直接将!stop转为true,当把代码优化成这样子以后,及时stop 变量改变为了false 也依然停止不了循环

解决方案:
第一:在程序运行的时候加入vm参数-Xint 表示禁用即时编辑器,不推荐,得不偿失(其他程序还要使用)
第二:在修饰stop 变量的时候加上volatile ,表示当前代码禁用了即时编辑器,问题
就可以解决


然后是禁止进行指令重排序,比如如下代码:

在这里插入图片描述
在去获取上面的结果的时候,有可能会出现4种情况
情况一:先执行actor2获取结果—>0,0(正常)
情况二:先执行actor1中的第一行代码,然后执行actor2获取结果—>0,1(正常)
情况三:先执行actor1中所有代码,然后执行actor2获取结果—>1,1(正常)
情况四:先执行actor1中第二行代码,然后执行actor2获取结果—>1,0(发生了指令重排序,影响结果)

解决方案:在变量上添加volatile,禁止指令重排序,则可以解决问题

在这里插入图片描述

屏障添加的示意图:

在这里插入图片描述

写操作加的屏障是阻止上方其它写操作越过屏障排到volatile变量写之下
读操作加的屏障是阻止下方其它读操作越过屏障排到volatile变量读之上

我们上面的解决方案是把volatile加在了int y这个变量上,我们能不能把它加在
int x这个变量上呢?如果使用volatile修饰了x变量,如下所示,这样显然是不行的

在这里插入图片描述

所以,现在我们就可以总结一个volatile使用的小妙招:

  • 写变量让volatile修饰的变量的在代码最后位置
  • 读变量让volatile修饰的变量的在代码最开始位置


AQS

全称是 Abstract Queued Synchronizer 它是构建锁或者其他同步组件的基础框架

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

AQS常见的实现类

  • ReentrantLock 阻塞式锁
  • Semaphore 信号量
  • CountDownLatch 倒计时锁

工作机制

  • 在AQS中维护了一个使用了volatile修饰的state属性来表示资源的状态,0表示无锁,1表示有锁
  • 提供了基于 FIFO 的等待队列,类似于 Monitor 的 EntryList
  • 条件变量来实现等待、唤醒机制,支持多个条件变量,类似于 Monitor 的WaitSet

线程0来了以后,去尝试修改state属性,如果发现state属性是0,就修改state状态为1,表示线程0抢锁成功
线程1和线程2也会先尝试修改state属性,发现state的值已经是1了,有其他线程持有锁,它们都会到FIFO队列中进行等待,
FIFO是一个双向队列,head属性表示头结点,tail表示尾结点

如果多个线程共同去抢这个资源是如何保证原子性的呢?在去修改state状态的时候,使用的cas自旋锁来保证原子性,确保只能有一个线程修改成功,修改失败的线程将会进入FIFO队列中等待

AQS是公平锁吗,还是非公平锁?

如果新的线程与队列中的线程共同来抢资源,是非公平锁
如果新的线程到队列中等待,只让队列中的head线程获取锁,是公平锁

比较典型的AQS实现类ReentrantLock,它默认就是非公平锁,新的线程与队
列中的线程共同来抢资源



ReentrantLock的实现原理

ReentrantLock翻译过来是可重入锁,相对于synchronized它多具备以下特点(面试题,与synchronized的区别):

  • 可中断
  • 可以设置超时时间
  • 可以设置公平锁
  • 支持多个条件变量
  • 与synchronized一样,都支持重入

在这里插入图片描述

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

工作流程

在这里插入图片描述

  • 线程来抢锁后使用cas的方式修改state状态,修改状态成功为1,则让exclusiveOwnerThread属性指向当前线程,获取锁成功
  • 假如修改状态失败,则会进入双向队列中等待,head指向双向队列头部,tail指向双向队列尾部
  • 当exclusiveOwnerThread为null的时候,则会唤醒在双向队列中等待的线程
  • 公平锁则体现在按照先后顺序获取锁,非公平体现在不在排队的线程也可以抢锁


synchronized和Lock有什么区别 ?

  • 语法层面
    • synchronized 是关键字,源码在 jvm 中,用 c++ 语言实现
    • Lock 是接口,源码由 jdk 提供,用 java 语言实现
    • 使用 synchronized 时,退出同步代码块锁会自动释放,而使用 Lock 时,需要手动调用 unlock 方法释放锁
  • 功能层面
    • 二者均属于悲观锁、都具备基本的互斥、同步、锁重入功能
    • Lock 提供了许多 synchronized 不具备的功能,例如获取等待状态、公平锁、可打断、可超时、多条件变量(重点 需要背)
    • Lock 有适合不同场景的实现,如 ReentrantLock, ReentrantReadWriteLock
  • 性能层面
    • 在没有竞争时,synchronized 做了很多优化,如偏向锁、轻量级锁,性能不赖
    • 在竞争激烈时,Lock 的实现通常会提供更好的性能


死锁产生的条件是什么?如何避免死锁?如何如何进行死锁诊断?

死锁:一个线程需要同时获取多把锁,这时就容易发生死锁
例如:t1 线程获得A对象锁,接下来想获取B对象的锁
t2 线程获得B对象锁,接下来想获取A对象的锁

产生死锁的四个必要条件:
1.互斥:该资源任意一个时刻只由一个线程占用。
2.占有且等待:一个线程因请求资源而阻塞时,对已获得的资源保持不放。
3.不可强占用:线程已获得的资源在未使用完之前不能被其他线程强行剥夺,只有自己使用完毕后才释放资源。
4.循环等待:若干线程之间形成一种头尾相接的循环等待资源关系。



如何预防死锁?破坏死锁的产生的必要条件即可:
1.破坏占有且等待∶一次性申请所有的资源。
2.破坏不可强占用︰占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源。
3.破坏循环等待︰靠按序申请资源来预防。按某一顺序申请资源,释放资源则反序释放。



当程序出现了死锁现象,我们可以使用jdk自带的工具:jps和 jstack
第一:jps查看运行的线程

在这里插入图片描述

第二:使用jstack查看线程运行的情况,下图是截图的关键信息 运行命令: jstack -l 46032

在这里插入图片描述

其他解决工具,可视化工具

  • jconsole
    用于对jvm的内存,线程,类 的监控,是一个基于 jmx 的 GUI 性能监控工具
    打开方式:java 安装目录 bin目录下 直接启动 jconsole.exe 就行
  • VisualVM:故障处理工具
    能够监控线程,内存情况,查看方法的CPU时间和内存中的对 象,已被GC的对象,反向查看分配的堆栈
    打开方式:java 安装目录 bin目录下 直接启动 jvisualvm.exe就行


ConcurrentHashMap

JDK1.7中concurrentHashMap

在这里插入图片描述

底层采用分段的数组+链表实现
提供了一个segment数组,在初始化ConcurrentHashMap 的时候可以指定数组的长度,默认是16,一旦初始化之后中间不可扩容
在每个segment中都可以挂一个HashEntry数组,数组里面可以存储具体的元素,HashEntry数组是可以扩容的
在HashEntry存储的数组中存储的元素,如果发生冲突,则可以挂单向链表

存储流程:
先去计算key的hash值,然后确定segment数组下标
再通过hash值确定hashEntry数组中的下标存储数据
在进行操作数据的之前,会先判断当前segment对应下标位置是否有线程进行操作,为了线程安全使用的是ReentrantLock进行加锁,如果获取锁是被会使用cas自旋锁进行尝试

JDK1.8中concurrentHashMap

在这里插入图片描述

在JDK1.8中,放弃了Segment臃肿的设计,数据结构跟HashMap的数据结构是一样的:数组+红黑树+链表
采用 CAS + Synchronized来保证并发安全进行实现

  • CAS控制数组节点的添加
  • synchronized只锁定当前链表或红黑二叉树的首节点,只要hash不冲突,就不
    会产生并发的问题 , 效率得到提升

并发程序出现问题的根本原因(并发三大特性)

Java并发编程三大特性

  • 原子性 一个线程在CPU中操作不可暂停,也不可中断,要不执行完成,要不不执行
  • 可见性 让一个线程对共享变量的修改对另一个线程可见
  • 有序性 即指令重排

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

原子性解决方案

synchronized:同步加锁
JUC里面的lock:加锁

内存可见性解决方案

synchronized
volatile(推荐)
LOCK

有序性解决方案

volatile




ThreadLocal详解

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

案例:使用JDBC操作数据库时,会将每一个线程的Connection放入各自的ThreadLocal中,从而保证每个线程都在各自的 Connection 上进行数据库的操作,避免A线程关闭了B线程的连接

三个主要方法:set(value) 设置值 get() 获取值 remove() 清除值


ThreadLocal的实现原理

在ThreadLocal中有一个内部类叫做ThreadLocalMap,类似于HashMap,ThreadLocalMap中有一个属性table数组,这个是真正存储数据的位置

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述




ThreadLocal-内存泄露问题

ThreadLocalMap中使用的 key为 ThreadLocal的弱引用,而value是强引用。所以,如果ThreadLocal没有被外部强引用的情况下,在垃圾回收的时候,key会被清理掉,而value 不会被清理掉。

这样一来,ThreadLocalMap中就会出现 key为null 的Entry。假如我们不做任何措施的话,value永远无法被GC回收,这个时候就可能会产生内存泄露。ThreadLocalMap实现中已经考虑了这种情况,在调用set() 、get() 、 remove()方法的时候,会清理掉key为 null 的记录。使用完ThreadLocal方法后最好手动调用removeO方法

static class Entry extends >WeakReference<ThreadLocal<?>> {
	Object value;
	Entry(ThreadLocal<?> k, Object v) {
		super(k);
		value = v; //强引用,不会被回收
	}
}

四种引用类型介绍这篇文章有:一文学完JVM所有知识点!

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

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

相关文章

JavaEE企业级分布式高级架构师课程

教程介绍 本课程主要面向1-5年及以上工作经验的Java工程师&#xff0c;大纲由IT界知名大牛 — 廖雪峰老师亲自打造&#xff0c;由来自一线大型互联网公司架构师、技术总监授课&#xff0c;内容涵盖深入spring5设计模式/高级web MVC开发/高级数据库设计与开发/高级响应式web开发…

arm作业3

key_inc.c #include"key_inc.h"void key1_it_config(){//使能GPIOF外设时钟RCC->MP_AHB4ENSETR | (0x1<<5);//将PF9设置为输入模式GPIOF->MODER & (~(0x3<<18));//设置由PF9管脚产生EXTI9事件EXTI->EXTICR3 & (~(0XFF<<8));EXTI-…

微服务(基础篇-002-Ribbon)

目录 Ribbon负载均衡&#xff08;1&#xff09; 负载均衡的原理&#xff08;1.1&#xff09; 负载均衡策略&#xff08;1.2&#xff09; Ribbon-IRule(1.2.1) 修改负载均衡的方法&#xff08;1.2.2&#xff09; 懒加载&#xff08;1.3&#xff09; 饥饿加载&#xff08;1…

【Linux】模拟实现shell(bash)

目录 常见的与shell互动场景 实现代码 全部代码 homepath()接口 const char *getUsername()接口 const char *getHostname()接口 const char *getCwd()接口 int getUserCommand(char *command, int num)接口 void commandSplit(char *in, char *out[])接口 int execut…

python每日可视化分析:从过去到现代数据分析的演进

分析目标 本文旨在探索数据分析发展历程中的关键时刻&#xff0c;包括重要人物的贡献和大事件的发生。通过对比不同年代的数据分析技术和方法&#xff0c;我们可以更好地理解数据分析如何成为今天决策制定不可或缺的一部分。 分析步骤 收集数据&#xff1a;搜集关于数据分析历…

【Redis】优惠券秒杀

全局唯一ID 全局唯一ID生成策略&#xff1a; UUIDRedis自增snowflake算法数据库自增 Redis自增ID策略&#xff1a;每天一个key&#xff0c;方便统计订单量ID构造是 时间戳 计数器 Component public class RedisIdWorker {// 2024的第一时刻private static final long BEGIN…

微服务(基础篇-001-介绍、Eureka)

目录 认识微服务&#xff08;1&#xff09; 服务架构演变&#xff08;1.1&#xff09; 单体架构&#xff08;1.1.1&#xff09; 分布式架构&#xff08;1.1.2&#xff09; 微服务&#xff08;1.1.3&#xff09; 微服务结构 微服务技术对比 企业需求 SpringCloud(1.2) …

[BIT]智慧社区综合管理云平台需求文档

智慧社区综合管理云平台需求文档 目录: 智慧社区综合管理云平台需求文档一、 项目前景和范围文档1.业务需求1.1 项目前景1.2 主要特性1.2.1 安全监控1.2.2 社区服务1.2.3 电子化档案 1.3 假设与依赖 2.项目范围2.1 功能实现2.2 验收标准2.3 可交付成果2.4 项目的除外责任2.5 制…

基于SpringBoot+Vue+Mybatis的408刷题小程序管理端

简介 原始数据&#xff1a;书目信息、章节信息、题目信息、系统菜单、系统角色、系统用户。 主要任务&#xff1a;系统主要采用spring boot作为后端框架&#xff0c;前端使用vueelementUI&#xff0c;为408刷题小程序提供一个方面的管理和维护的任务&#xff0c;主要功能包括…

centos glibc 升级导致系统崩溃

centos 7.9默认的glibc为2.17&#xff0c;因为要安装一些软件&#xff0c;需要升级到glibc 2.18&#xff0c;而从源码进行编译和安装&#xff0c;安装失败&#xff0c;导致系统崩溃。 系统崩溃首先想到的是利用启动盘进行救援&#xff0c;而利用centos 7.9的启动盘始终无法挂载…

AI:152- 利用深度学习进行手势识别与控制

本文收录于专栏:精通AI实战千例专栏合集 从基础到实践,深入学习。无论你是初学者还是经验丰富的老手,对于本专栏案例和项目实践都有参考学习意义。 每一个案例都附带关键代码,详细讲解供大家学习,希望可以帮到大家。正在不断更新中~ 一. 利用深度学习进行手势识别与控制 …

jetcache 2级缓存模式实现批量清除

需求 希望能够实现清理指定对象缓存的方法&#xff0c;例如缓存了User表&#xff0c;当User表巨大时&#xff0c;通过id全量去清理不现实&#xff0c;耗费资源也巨大。因此需要能够支持清理指定本地和远程缓存的批量方法。 分析 查看jetcache生成的cache接口&#xff0c;并没…

nodejs+vue高校失物招领平台python-flask-django-php

时代在飞速进步&#xff0c;每个行业都在努力发展现在先进技术&#xff0c;通过这些先进的技术来提高自己的水平和优势&#xff0c;高校失物招领平台当然不能排除在外。高校失物招领平台是在实际应用和软件工程的开发原理之上&#xff0c;运用nodejs语言以及express框架进行开发…

如何在 Django 中使用 pyecharts

为项目新建一个目录&#xff0c;将其命名为django_pyecharts_demo, 在终端中切换到这个目录&#xff0c;并创建一个虚拟环境。 python -m venv django_pyecharts激活虚拟环境 django_pyecharts\Scripts\activate要停止使用虚拟环境&#xff0c;可执行命令 deactivate创建并激…

音视频领域首个,阿里云推出华为鸿蒙 HarmonyOS NEXT 版音视频 SDK

近日&#xff0c;阿里云在官网音视频终端 SDK 栏目发布适配 HarmonyOS NEXT 的操作文档和 SDK&#xff0c;官宣 MediaBox 音视频终端 SDK 全面适配 HarmonyOS NEXT。 此外&#xff0c;阿里云播放器 SDK 也在华为开发者联盟官网鸿蒙生态伙伴 SDK 专区同步上线&#xff0c;面向所…

Docker进阶:Docker-cpmpose 实现服务弹性伸缩

Docker进阶&#xff1a;Docker-cpmpose 实现服务弹性伸缩 一、Docker Compose基础概念1.1 Docker Compose简介1.2 Docker Compose文件结构 二、弹性伸缩的原理和实现步骤2.1 弹性伸缩原理2.2 实现步骤 三、技术实践案例3.1 场景描述3.2 配置Docker Compose文件3.3 使用 docker-…

6.4 Dropout正则化

1、Dropout Dropout是一种正则化技术&#xff0c;通过防止特征的协同适应&#xff0c;可用于减少神经网络中的过拟合。 Dropout的效果非常好&#xff0c;实现简单且不会降低网络速度&#xff0c;被广泛使用。 特征的协同适应指的是在训练模型时&#xff0c;共同训练的神经元…

Unity构建详解(3)——SBP的依赖计算

【前置知识】 先要搞清楚Asset和Object的关系&#xff0c;可以简单理解为一个Asset对应多个Object。 unity自定义的Asset也要有一个存储的标准&#xff0c;其采用的是YAML&#xff0c;我们看到的所有Unity自定义的Asset格式&#xff0c;例如.prefab&#xff08;预制体&#x…

基于Google云原生工程师的kubernetes最佳实践(三)

目录 三、集群管理 利用node affinity、taint等机制管理node 通过pod affinity/anti-affinity机制将pod分配到合适的node Node分级管理 从Qos角度将Pod分级 用namespace隔离不同的环境和用户 配置RBAC权限控制 1. 遵循最小权限原则 2. 使用 Role 和 ClusterRole 分离权…

计算机服务器中了faust勒索病毒怎么办,faust勒索病毒解密工具流程

网络是一把利剑&#xff0c;可以方便企业开展各项工作业务&#xff0c;为企业提供极大的便利&#xff0c;但随着网络技术的不断发展与应用&#xff0c;网络数据安全威胁也在不断增加&#xff0c;给企业的正常生产运营带来了极大困扰&#xff0c;近日&#xff0c;云天数据恢复中…