Java多线程核心技术一-基础篇synchronzied同步语句块

 接上篇:Java多线程核心技术二-synchronzied同步方法

1 概述

        用synchronzied关键字声明方法在某些情况下是有弊端的,比如A线程调用同步方法执行一个长时间的任务,那么B现成就要等待比较长的时间,此时可以使用synchronzied同步语句块来解决,已增加运行效率。

        synchronzied方法是将当前对象作为锁,而synchronzied代码块是将任意对象作为锁。锁可以认为是一个标识,持有这个标识的线程就可以执行被同步的代码。

2 synchronzied方法的弊端

        下面证明用synchronzied关键字声明方法时是有弊端的。

public class Task {
    private String getData1;
    private String getData2;
    
    public synchronized void doLongTimeTask(){
        try {
            System.out.println("任务开始");
            Thread.sleep(3000);
            getData1 = "长时间处理任务后,从远程返回的值1线程名=" + Thread.currentThread().getName();
            getData2 = "长时间处理任务后,从远程返回的值2线程名=" + Thread.currentThread().getName();
            System.out.println(getData1);
            System.out.println(getData2);
            System.out.println("任务结束");
            
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}
public class CommonUtils {
    public static long beginTime1;
    public static long endTime1;
    public static long beginTime2;
    public static long endTime2;
}
public class MyThread1 extends Thread{
    private Task task;

    public MyThread1(Task task) {
        this.task = task;
    }
    @Override
    public void run(){
        CommonUtils.beginTime1 = System.currentTimeMillis();
        task.doLongTimeTask();
        CommonUtils.endTime1 = System.currentTimeMillis();
    }
}
public class MyThread2 extends Thread{
    private Task task;

    public MyThread2(Task task) {
        this.task = task;
    }
    @Override
    public void run(){
        CommonUtils.beginTime2 = System.currentTimeMillis();
        task.doLongTimeTask();
        CommonUtils.endTime2 = System.currentTimeMillis();
    }
}
public class Run1 {
    public static void main(String[] args) {
        Task task = new Task();
        MyThread1 t1 = new MyThread1(task);
        t1.start();
        MyThread2 t2 = new MyThread2(task);
        t2.start();
        try {
            Thread.sleep(10000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        long beginTime = CommonUtils.beginTime1;
        if(CommonUtils.beginTime2 < CommonUtils.beginTime1){
            beginTime = CommonUtils.beginTime2;
        }
        long endTime = CommonUtils.endTime1;
        if(CommonUtils.endTime2 > CommonUtils.endTime1){
            endTime = CommonUtils.endTime2;
        }
        System.out.println("耗时:"+((endTime - beginTime) /1000) + "秒");
    }
}

        通过使用synchronzied关键字来声明方法,从运行的时间上来看,弊端很明显,可以使用synchronzied同步代码块来解决。

3 synchronzied同步代码块的使用

        先来了解一下synchronzied同步代码块的使用方法。当两个并发线程访问同一个对象object中的synchronzied(this)同步代码块时,一个时间内只能执行一个线程,另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。

public class ObjectService {
    public void serviceMethod(){
        try {
            synchronized (this){
                System.out.println("线程名 = " + Thread.currentThread().getName() + "开始时间 = " + System.currentTimeMillis());
                Thread.sleep(2000);
                System.out.println("线程名 = " + Thread.currentThread().getName() +"结束时间 = " + System.currentTimeMillis());
            }
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

public class ThreadA extends Thread{
    private ObjectService objectService;

    public ThreadA(ObjectService objectService) {
        this.objectService = objectService;
    }
    @Override
    public void run(){
        objectService.serviceMethod();
    }
}
public class ThreadB extends Thread{
    private ObjectService service;

    public ThreadB(ObjectService service) {
        this.service = service;
    }

    @Override
    public void run(){
        service.serviceMethod();
    }
}
public class Run1 {
    public static void main(String[] args) {
        ObjectService service = new ObjectService();
        ThreadA a = new ThreadA(service);
        a.setName("a");
        a.start();
        ThreadB b = new ThreadB(service);
        b.setName("b");
        b.start();
    }
}

        上面的例子虽然使用了synchronzied同步代码块,但执行的效率没有提高,还是同步运行。如何用synchronzied同步代码块解决程序执行效率慢的问题呢?

4 用同步代码块解决同步方法的弊端

        【示例】 

public class Task {
    private String getData1;
    private String getData2;

    public  void doLongTimeTask(){
        try {
            System.out.println("开始任务:");
            Thread.sleep(3000);
            String privateGetData1 = "长时间处理任务后,从远程返回的值1 线程名 = " + Thread.currentThread().getName();
            String privateGetData2 = "长时间处理任务后,从远程返回的值2 线程名 = " + Thread.currentThread().getName();
            synchronized (this){
                getData1 = privateGetData1;
                getData2 = privateGetData2;
                System.out.println(getData1);
                System.out.println(getData2);
                System.out.println("任务结束。");
            }
        }catch (InterruptedException e){
            e.printStackTrace();
        }

    }
}
public class MyThread1 extends Thread{
    private Task task;

    public MyThread1(Task task) {
        this.task = task;
    }
    @Override
    public void run(){
        CommonUtils.beginTime1 = System.currentTimeMillis();
        task.doLongTimeTask();
        CommonUtils.endTime1 = System.currentTimeMillis();
    }
}
public class MyThread2 extends Thread{
    private Task task;

    public MyThread2(Task task) {
        this.task = task;
    }
    @Override
    public void run(){
        CommonUtils.beginTime2 = System.currentTimeMillis();
        task.doLongTimeTask();
        CommonUtils.endTime2 = System.currentTimeMillis();
    }
}
public class Run1 {
    public static void main(String[] args) {
        Task task = new Task();
        MyThread1 t1 = new MyThread1(task);
        t1.start();
        MyThread2 t2 = new MyThread2(task);
        t2.start();
        try {
            Thread.sleep(10000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        long beginTime = CommonUtils.beginTime1;
        if(CommonUtils.beginTime2 < CommonUtils.beginTime1){
            beginTime = CommonUtils.beginTime2;
        }
        long endTime = CommonUtils.endTime1;
        if(CommonUtils.endTime2 > CommonUtils.endTime1){
            endTime = CommonUtils.endTime2;
        }
        System.out.println("耗时:"+((endTime - beginTime) /1000) + "秒");
    }
}

        通过上面的示例可以看出,当一个线程访问object对象的一个synchronzied同步代码块时,另一个线程仍然可以访问该对象中的非synchronzied同步代码块。在这个示例中,虽然时间缩短了,加快了运行效率,但同步synchronzied代码块真的是同步的吗?它真的持有当前调用对象的锁吗?是的,但必须通过下个例子来验证。

5 一半异步,一半同步 

        本节示例用于说明不在synchronzied代码块中就是异步执行,在synchronzied代码块中就是同步执行。

public class Task {
    public void doLongTimeTask(){
        for (int i = 0; i < 100; i++) {
            System.out.println("没有执行同步方法的线程名 = " + Thread.currentThread().getName() + "i=" + (i+1));
        }
        System.out.println("");
        synchronized (this){
            for (int i = 0; i < 100; i++) {
                System.out.println("执行同步方法的线程名 = " + Thread.currentThread().getName() + "i=" + (i+1));
            }
        }
    }
}
public class MyThread1 extends Thread{
    private Task task;

    public MyThread1(Task task) {
        this.task = task;
    }
    @Override
    public  void run(){
        task.doLongTimeTask();
    }
}
public class MyThread2 extends Thread{
    private Task task;

    public MyThread2(Task task) {
        this.task = task;
    }
    @Override
    public  void run(){
        task.doLongTimeTask();
    }
}
public class Run1 {
    public static void main(String[] args) {
        Task task = new Task();
        MyThread1 a = new MyThread1(task);
        a.start();
        MyThread2 b = new MyThread2(task);
        b.start();
    }
}

根据运行结果可知,在执行没有同步代码块的时候,两个线程之间互相竞争资源。进入同步代码块后,两个线程被排队执行。

6 synchronzied代码块间的同步性

        在使用synchronzied同步代码块时需要注意,当一个线程访问object的一个synchronzied同步代码块时,其他线程对同一个object中的所有其他synchronzied同步代码块的访问都被阻塞,说明synchronzied使用的对象监视器是一个,即使用的“锁”是一个。通过示例验证。

public class ObjectService {
    public void serviceMethodA(){
        try {
            synchronized (this){
                System.out.println("方法A开始执行时间" + System.currentTimeMillis());
                Thread.sleep(2000);
                System.out.println("方法A结束时间" + System.currentTimeMillis());
            }
        }catch (InterruptedException e){

        }
    }

    public void serviceMethodB(){
        synchronized (this){
            System.out.println("方法B开始执行时间 = " + System.currentTimeMillis());
            System.out.println("方法B结束时间 = " + System.currentTimeMillis());
        }
    }
}
public class ThreadA extends Thread{
    private ObjectService objectService;

    public ThreadA(ObjectService objectService) {
        this.objectService = objectService;
    }

    @Override
    public void  run(){
        objectService.serviceMethodA();
    }
}
public class ThreadB extends Thread{
    private ObjectService objectService;

    public ThreadB(ObjectService objectService) {
        this.objectService = objectService;
    }

    @Override
    public void run(){
        objectService.serviceMethodB();
    }
}
public class Run1 {
    public static void main(String[] args) {
        ObjectService service = new ObjectService();
        ThreadA a = new ThreadA(service);
        a.setName("a");
        a.start();
        ThreadB b = new ThreadB(service);
        b.setName("b");
        b.start();
    }
}

7 将任意对象作为锁

        多个线程调用同一个对象中的不同名称的synchronzied同步方法或同步代码块,是按顺序执行,也就是同步的。

        如果在一个类中同时存在synchronzied同步方法和同步代码块,对其他synchronzied同步方法或同步代码块调用会呈同步的效果,执行特性如下:

        1、同一个时间只有一个线程可以执行synchronzied同步方法中的代码。

        2、同一时间只有一个线程可以执行synchronzied同步代码块中的代码。

        其中Java还支持将任意对象作为锁,来实现同步的功能,这个任意对象大多数是实例变量及方法的参数,格式为synchronzied(非this对象)。

        synchronzied(非this对象)同步代码块的执行特性是:在多个线程争抢相同的非this对象的锁时,同一时间只有一个线程可以执行synchronzied同步代码块中的代码。

public class Service {
    private String usernameParam;
    private String passwordParam;
    private String anyString = new String();
    public void  setUsernamePassword(String username,String password){
        try {
            synchronized (anyString){
                System.out.println("线程名为:"+ Thread.currentThread().getName() + "在" +System.currentTimeMillis() + "进入同步代码块");
                usernameParam = username;
                Thread.sleep(3000);
                passwordParam = password;
                System.out.println("线程名为:"+ Thread.currentThread().getName() + "在" +System.currentTimeMillis() + "离开同步代码块");
            }
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}
public class ThreadA extends Thread{
    private Service service;

    public ThreadA(Service service) {
        this.service = service;
    }
    @Override
    public void run(){
        service.setUsernamePassword("a","aa");
    }
}
public class ThreadB extends Thread{
    private Service service;

    public ThreadB(Service service) {
        this.service = service;
    }
    @Override
    public void run(){
        service.setUsernamePassword("b","bb");
    }
}
public class Run1 {
    public static void main(String[] args) {
        Service service = new Service();
        ThreadA a = new ThreadA(service);
        a.setName("A");
        a.start();
        ThreadB b = new ThreadB(service);
        b.setName("B");
        b.start();
    }
}

总结:锁非this对象具有一定的优点,就是如果一个类中有很多synchronzied方法,这时虽然能是实现同步,但影响运行效率,如果使用同步代码块锁非this对象,则synchronzied代码块中的程序与同步方法是异步的,因为是两把锁,不与其他锁this同步方法争抢this锁,可以提高运行效率。

8 验证方法被调用是随机的

        同步代码块放在非同步synchronzied方法中进行声明,并不能保证调用方法的线程的执行顺序,即线程调用方法是无序的,下面来验证多个线程调用同一个方法是随机的。

public class MyList {
    private List list = new ArrayList<>();
    synchronized public void add(String username){
        System.out.println("线程 " + Thread.currentThread().getName() + "执行了 add 方法");
        list.add(username);
        System.out.println("线程 " + Thread.currentThread().getName() + "退出了 add 方法");
    }

}

public class ThreadA extends Thread{
    private MyList myList;

    public ThreadA(MyList myList) {
        this.myList = myList;
    }

    @Override
    public void run(){
        for (int i = 0; i < 50000; i++) {
            myList.add("thread_a " + (i+1));
        }
    }
}
public class ThreadB extends Thread{
    private MyList myList;

    public ThreadB(MyList myList) {
        this.myList = myList;
    }

    @Override
    public void run(){
        for (int i = 0; i < 50000; i++) {
            myList.add("thread_b"+ (i+1));
        }
    }
}
public class Run1 {
    public static void main(String[] args) {
        MyList myList = new MyList();
        ThreadA a = new ThreadA(myList);
        a.setName("a");
        a.start();
        ThreadB b = new ThreadB(myList);
        b.setName("b");
        b.start();
    }
}

        从运行结果来看,同步方法中的代码是同步输出的,所以线程的“执行”与“退出”是成对出现的,但是方法被调用是随机的,也就是线程A和线程B的执行是异步的。 

9 静态同步:synchronzied方法与synchronzied(class)代码块

        synchronzied关键字还可以应用在静态方法上,如果这些写,那是对当前的*.java文件对应的Class类的对象进行持锁,Class类的对象是单例的,更具体的说,在静态方法上使用synchronzied关键字声明同步方法时,是使用当前静态方法所在类对应Class类的单例对象作为锁的。

public class Service {
    synchronized public static void printA(){
        try {
            System.out.println("线程名为:"+ Thread.currentThread().getName() + "在" +
                    System.currentTimeMillis() + "进入printA方法");
            Thread.sleep(3000);
            System.out.println("线程名为:"+ Thread.currentThread().getName() + "在" +
                    System.currentTimeMillis() + "退出printA方法");
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    synchronized public static void printB(){
        System.out.println("线程名为:"+ Thread.currentThread().getName() + "在" +
                System.currentTimeMillis() + "进入printA方法");
        System.out.println("线程名为:"+ Thread.currentThread().getName() + "在" +
                System.currentTimeMillis() + "退出printA方法");
    }
}
public class ThreadA extends Thread{
    @Override
    public void run(){
        Service.printA();
    }
}
public class ThreadB extends Thread{

    @Override
    public void run(){
        Service.printB();
    }
}
public class Run1 {
    public static void main(String[] args) {
        ThreadA a = new ThreadA();
        a.setName("a");
        a.start();
        ThreadB b = new ThreadB();
        b.setName("b");
        b.start();
    }
}

        虽然运行结果与将synchronzied关键字加到非static静态方法上的效果一样,都是同步的效果,但还是有本质上的不同。synchronzied关键字加到static静态方法上是将Class类的对象作为锁,而synchronzied关键字加到非static静态方法上是将方法所在类的对象作为锁。

10 同步synchronzied方法可以对类的所有对象实例起作用

        Class锁可以对同一个类的所有对象实例起作用,实现同步效果。

public class Service {

    synchronized public static void printA(){
        try {
            System.out.println("线程名为:"+ Thread.currentThread().getName() + "在" +
                    System.currentTimeMillis() + "进入printA方法");
            Thread.sleep(3000);
            System.out.println("线程名为:"+ Thread.currentThread().getName() + "在" +
                    System.currentTimeMillis() + "退出printA方法");
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
    synchronized public static void printB(){
        System.out.println("线程名为:"+ Thread.currentThread().getName() + "在" +
                System.currentTimeMillis() + "进入printB方法");
        System.out.println("线程名为:"+ Thread.currentThread().getName() + "在" +
                System.currentTimeMillis() + "退出printB方法");
    }
}
public class ThreadA extends Thread{
    private Service service;

    public ThreadA(Service service) {
        this.service = service;
    }
    @Override
    public void run(){
        service.printA();
    }
}
public class ThreadB extends Thread{
    private Service service;

    public ThreadB(Service service) {
        this.service = service;
    }

    @Override
    public void run(){
        service.printB();
    }
}
public class Run1 {
    public static void main(String[] args) {
        Service s1 = new Service();
        ThreadA a = new ThreadA(s1);
        a.setName("A");
        a.start();
        Service s2 = new Service();
        ThreadB b = new ThreadB(s2);
        b.setName("B");
        b.start();
    }
}

        虽然是不同的对象,但静态的同步方法还是同步运行了。

11 同步synchronzied(class)代码块可以对类的所有对象实例起作用

        同步代码块的作用其实和同步静态方法的作用一样。

public class Service {
    public void printA(){
        synchronized (Service.class){
            try {
                System.out.println("线程名为:"+ Thread.currentThread().getName() + "在" +
                        System.currentTimeMillis() + "进入printA方法");
                Thread.sleep(3000);
                System.out.println("线程名为:"+ Thread.currentThread().getName() + "在" +
                        System.currentTimeMillis() + "退出printA方法");
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }

    public void printB(){
        synchronized (Service.class){
            System.out.println("线程名为:"+ Thread.currentThread().getName() + "在" +
                    System.currentTimeMillis() + "进入printB方法");
            System.out.println("线程名为:"+ Thread.currentThread().getName() + "在" +
                    System.currentTimeMillis() + "退出printB方法");
        }
    }
}
public class ThreadA extends Thread{
    private Service service;

    public ThreadA(Service service) {
        this.service = service;
    }

    @Override
    public void run(){
        service.printA();
    }
}

public class ThreadB extends Thread{
    private Service service;

    public ThreadB(Service service) {
        this.service = service;
    }
    @Override
    public void run(){
        service.printB();
    }
}
public class Run1 {
    public static void main(String[] args) {
        Service s1 = new Service();
        Service s2 = new Service();
        ThreadA a = new ThreadA(s1);
        a.setName("A");
        a.start();
        ThreadB b = new ThreadB(s2);
        b.setName("B");
        b.start();
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

nexus 制品库管理

目录 一、nexus 介绍 二、nexus 支持的仓库 三、nexus 部署 四、nexus 数据备份 五、创建一个内网yum源 六、创建一个代理yum仓库 七、jenkins 使用 nexus插件 7.1 jenkins 安装插件 7.2 配置 maven 工程 7.3 查看构建和上传 一、nexus 介绍 Nexus 是一个强大的仓库管…

Linux创建与编辑视图

本博客将会详细讲解如何在Linux中如何编辑配置文件 输出重定向 对于一台设备而言&#xff0c;存在着两种设备&#xff0c;分别负责输入与输出&#xff1a; 显示器&#xff08;输出设备>&#xff09; 与 键盘&#xff08;输入设备<&#xff09; 对于Linux系统而言&#…

存储过程与触发器的练习题

1&#xff0e;实验目的 掌握使用SQL Server管理平台和Transact-SQL语句创建存储过程、执行存储过程、修改存储过程、删除存储过程的用法。理解使用SQL Server管理平台和Transact-SQL语句查看存储过程定义、重命名存储过程的用法。掌握通过SQL Server管理平台和Transact-SQL语句…

【古月居《ros入门21讲》学习笔记】18_常用可视化工具的使用

目录 说明&#xff1a; 1. Qt工具箱 日志输出工具&#xff1a;rqt_console 绘制数据曲线&#xff1a;rqt_plot 图像渲染工具&#xff1a;rqt_image_view 综合工具&#xff1a;rqt 2. 三维可视化工具&#xff1a;Rviz Rviz启动 使用示例 3. 仿真平台&#xff1a;Gazebo…

通用plantuml模板头

通用plantuml文件 startuml participant Admin order 0 #87CEFA // 参与者、顺序、颜色 participant Student order 1 #87CEFA participant Teacher order 2 #87CEFA participant TestPlayer order 3 #87CEFA participant Class order 4 #87CEFA participant Subject order …

004:Direct 2D离屏渲染(Qt中实现)

简介&#xff1a; 用QT开发图像显示的小程序&#xff0c;需要一些标注工具&#xff0c;由于用的是opengl渲染&#xff0c;所以就在内存中进行绘制&#xff0c;然后纹理贴图贴出去&#xff0c;发现Qt绘制的效果太差&#xff0c;且速度一般&#xff0c;于是就想着用direct2d来绘制…

MySQL根据binlog恢复数据

简介 本文介绍了使用mysqlbinlog导出数据&#xff0c;根据binlog恢复数据&#xff0c;和导出数据时报需要super权限的解决方法。 环境 MySQL: 5.7.40 说明 MySQL的binlog是数据库服务器在运行过程中产生的日志文件&#xff0c;记录了数据库增删改的操作&#xff0c;可用于恢复和…

leetcode二叉树

下面的两个题呢是比较类似的所以放在一起讲&#xff0c;更好的理解起来。 https://leetcode.cn/problems/same-tree/description/ 这个题就是比较两颗树是不是一样的&#xff0c;这个其实看起来就只要比较当前节点&#xff0c;我们分析成子问题就是判断两颗树当前节点是不是一致…

Java实现动态加载的逻辑

日常工作中我们经常遇到这样的场景&#xff0c;某某些逻辑特别不稳定&#xff0c;随时根据线上实际情况做调整&#xff0c;比如商品里的评分逻辑&#xff0c;比如规则引擎里的规则。 常见的可选方案有: JDK自带的ScriptEngine 使用groovy&#xff0c;如GroovyClassLoader、Gro…

《尚品甄选》:后台系统——分类品牌和规格管理(debug一遍)

文章目录 一、分类品牌管理1.1 表结构介绍1.2 列表查询1.3 添加功能1.4 修改功能1.5 删除功能 二、商品规格管理2.1 表结构介绍2.2 列表查询2.3 添加功能2.4 修改功能2.5 删除功能 一、分类品牌管理 分类品牌管理就是将分类的数据和品牌的数据进行关联&#xff0c;分类数据和品…

48、Flink DataStream API 编程指南(1)- DataStream 入门示例

Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…

Web安全漏洞分析-XSS(中)

随着互联网的迅猛发展&#xff0c;Web应用的普及程度也愈发广泛。然而&#xff0c;随之而来的是各种安全威胁的不断涌现&#xff0c;其中最为常见而危险的之一就是跨站脚本攻击&#xff08;Cross-Site Scripting&#xff0c;简称XSS&#xff09;。XSS攻击一直以来都是Web安全领…

微信小程序本地和真机调试文件上传成功但体验版不成功

可能是微信小程序ip白名单的问题&#xff0c;去微信公众平台&#xff08;小程序&#xff09;上设置小程序的ip白名单 1、在本地中取消不校验 然后在本地去上传文件&#xff0c;就会发现控制台报错了&#xff0c;会提示一个https什么不在ip白名单&#xff0c;复制那个网址 2、…

【中间件】DAL中间件intro

中间件middleware 内容管理 intro数据访问层why use DAL中间件主流DAL中间件方案DAL浅析 本文从理论上介绍一下服务化背景下的DAL中间件的理论并浅析相关中间件 cfeng之前work的时候产品发展到分离服务不分库的阶段&#xff0c;所以根本不需要DAL中间件&#xff0c;也没有分布式…

机器学习——决策树

1.决策树 2.熵&#xff08;不确定程度&#xff09; 3.信息增益 & 信息增益比 3.1 信息增益 & 信息增益比 的 概念 3.2 案例解释说明 &#xff13;.&#xff12;.&#xff11;数据集说明 &#xff13;.&#xff12;.&#xff12;计算 &#xff14;&#xff0e;&#x…

软件设计师——计算机组成原理(一)

&#x1f4d1;前言 本文主要是【计算机组成原理】——软件设计师计算机组成原理的习题&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 &…

[React] 2023年最新面试题

[React] 2023年最新面试题 1. class 组件与函数组件的区别2. react 18 新特性有那些?新增 createRoot API自动批处理过渡更新新的Hook 3. redux 和 react-redux 的区别4. redux 中间件的原理5. setState 发生了什么 &#xff0c;render 函数做了什么6. 虚拟DOM&#xff0c; Fi…

海外储能认证标准

北美认证 UL9540 代表一个封装完整的储能系统功能安全认证&#xff0c;关注机械测试&#xff0c;电器测试和环境测试 UL9540A 关注消防本身&#xff0c;UL9540A测试主要从电池储能系统安装参数&#xff0c;安装通风要求&#xff0c;消防设施&#xff0c;消防策略和应对措施…

SpringCloud 一

认识微服务 随着互联网行业的发展&#xff0c;对服务的要求也越来越高&#xff0c;服务架构也从单体架构逐渐演变为现在流行的微服务架构。这些架构之间有怎样的差别呢&#xff1f; 单体架构 单体架构&#xff1a;将业务的所有功能集中在一个项目中开发&#xff0c;打成一个…

springmvc实验(三)——请求映射

【知识要点】 方法映射概念 所谓的方法映射就是将前端发送的请求地址和后端提供的服务方法进行关联。在springMVC框架中主要使用Controller和RequestMapping两个注解符&#xff0c;实现请求和方法精准匹配。注解符Controller Spring中包含了一个Controller接口&#xff0c;但是…