java多线程编程面试题总结

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

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所有知识点!

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

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

相关文章

CSS案例-2.简单版侧边栏练习

效果 知识点 标签显示模式 块级元素 block-level 常见元素:<h1>~<h6>、<p>、<div>、<ul>、<ol>、<li>等。 特点: 独占一行长度、宽度、边距都可以控制宽度默认是容器(父级宽度)的100%是一个容器及盒子,里面可以放行内或者…

spring注解驱动系列--AOP探究二

上篇中记录了AnnotationAwareAspectJAutoProxyCreator的创建以及注册&#xff0c;主要是 1、EnableAspectJAutoProxy 注解会开启AOP功能 2、然后这个注解会往容器中注册一个AnnotationAwareAspectJAutoProxyCreator组件。 3、之后在容器创建过程中&#xff0c;注册后置处理器&a…

【免费】【随机优化】智能配电网的双时间尺度随机优化调度

目录 1 主要内容 2 部分代码 3 部分程序结果 4 下载链接 1 主要内容 该程序为文章《Two-Timescale Stochastic Dispatch of Smart Distribution Grids》的源代码&#xff0c;主要做的是主动配电网的双时间尺度随机优化调度&#xff0c;该模型考虑配电网的高效和安全运行涉及…

【大模型】在VS Code(Visual Studio Code)上安装中文汉化版插件

文章目录 一、下载安装二、配置显示语言&#xff08;一&#xff09;调出即将输入命令的搜索模式&#xff08;二&#xff09;在大于号后面输入&#xff1a;Configure Display Language&#xff08;三&#xff09;重启 三、总结 【运行系统】win 11 【本文解决的问题】 1、英文不…

【JS】如何避免输入中文拼音时触发input事件

现有一段代码&#xff0c;监听input事件。 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" con…

GDC期间LayaAir启动全球化战略

3 月 18 日至 3 月 22 日&#xff0c;一年一度的游戏开发者大会&#xff08;GDC&#xff09;在美国旧金山举行。在此期间&#xff0c;Layabox宣布LayaAir引擎启动全球扩张战略&#xff0c;这标志着引擎将步入快速发展的新阶段。此举旨在利用公司先进的3D引擎技术&#xff0c;将…

mysql体系结构及主要文件

目录 1.mysql体系结构 2.数据库与数据库实例 3.物理存储结构​编辑 4.mysql主要文件 4.1数据库配置文件 4.2错误日志 4.3表结构定义文件 4.4慢查询日志 4.4.1慢查询相关参数 4.4.2慢查询参数默认值 4.4.3my.cnf中设置慢查询参数 4.4.4slow_query_log参数 4.4.…

B端设计:如何让UI组件库成为助力,而不是阻力。

首发2023-09-24 15:42贝格前端工场 Hi&#xff0c;我是大千UI工场&#xff0c;网上的UI组件库琳琅满目&#xff0c;比如elementUI、antdesign、iview等等&#xff0c;甚至很多前端框架&#xff0c;也出了很多UI组件&#xff0c;如若依、Layui、bootstrap等等&#xff0c;作为U…

01.数据归档工具的选择-Percona Toolkit,并centos7.9中安装

1.需求 1.1.在实际的业务使用过程中&#xff0c;我们既要考虑服务器硬件的成本&#xff0c;也要考虑系统的稳定性。所以就有了数据归档的这个业务需求了。我们需要把一些老的数据&#xff0c;比如两年前的数据移出去。增强数据库的性能。 1.2.在进行数据归档的过程中&#xf…

【云开发笔记No.6】腾讯CODING平台

腾讯云很酷的一个应用&#xff0c;现在对于研发一体化&#xff0c;全流程管理&#xff0c;各种工具层出不穷。 云时代用云原生&#xff0c;再加上AI&#xff0c;编码方式真是发生了质的变化。 从前&#xff0c;一个人可以写一个很酷的软件&#xff0c;后来&#xff0c;这变得…

RDGCN翻译

RDGCN翻译 Relation-Aware Entity Alignment for Heterogeneous Knowledge Graphs 面向异质知识图谱的关系感知实体对齐 阅读时间&#xff1a;2024.03.24 领域&#xff1a;知识图谱&#xff0c;知识对齐 作者&#xff1a;Yuting Wu等人 PKU 出处&#xff1a;IJCAI Abstract…

蓝桥杯 2023 省A 颜色平衡树

树上启发式合并是一个巧妙的方法。 dsu on tree&#xff0c;可以称为树上启发式合并&#xff0c;是一种巧妙的暴力。用一个全局数组存储结果&#xff0c;对于每棵子树&#xff0c;有以下操作&#xff1a; 先遍历轻儿子&#xff0c;处理完轻儿子后将数组清零&#xff08;要再…

小目标检测篇 | YOLOv8改进之增加小目标检测层(针对Neck网络为AFPN)

前言:Hello大家好,我是小哥谈。小目标检测是计算机视觉领域中的一个研究方向,旨在从图像或视频中准确地检测和定位尺寸较小的目标物体。相比于常规目标检测任务,小目标检测更具挑战性,因为小目标通常具有低分辨率、低对比度和模糊等特点,容易被背景干扰或遮挡。本篇文章就…

stm32启动文件里面的__main和主函数main()

一、__main和main()之间的关系 先来对stm32启动过程简单学习 启动文件里面的Reset_Handler&#xff1a; 调用过程&#xff1a; stm32在启动后先进入重启中断函数Reset_Handler&#xff0c;其中会先后调用SystemInit和__main函数&#xff0c; __main函数属于c库函数&…

[Java基础揉碎]final关键字

目录 介绍 在某些情况下&#xff0c;程序员可能有以下需求&#xff0c;就会使用到final final注意事项和讨论细节 1) final修饰的属性又叫常量&#xff0c;一般用XX_XX_XX来命名 2) final修饰的属性在定义时&#xff0c;必须赋初值&#xff0c;并且以后不能再修改&#…

chatgpt和 github copilot chat哪个更强

chatgpt大家应该都不陌生 ChatGPT 是由 OpenAI 开发的一种基于 GPT&#xff08;生成式预训练模型&#xff09;的聊天机器人。它可以生成语言上下文相关的响应&#xff0c;从而进行自然语言对话。ChatGPT 利用大规模的语言数据进行预训练&#xff0c;并通过微调或在线学习来适应…

【】(综合练习)博客系统

在之前的学些中&#xff0c;我们掌握了Spring框架和MyBatis的基本使用&#xff0c;接下来 我们就要结合之前我们所学的知识&#xff0c;做出一个项目出来 1.前期准备 当我们接触到一个项目时&#xff0c;我们需要对其作出准备&#xff0c;那么正规的准备是怎么样的呢 1.了解需求…

vue3项目初始化

初始化项目newsapp VSCode 打开终端&#xff0c;newsapp项目目录&#xff0c;可自定义 vue create newsapp 有提示“因为在此系统上禁止运行脚本”的话&#xff0c;请执行 set-ExecutionPolicy RemoteSigned 执行后再重复执行vue create newsapp 注意选择Vue 3版本 测试项…

【案例分析】入职第一天,如何让同事对我刮目相看

背景 在办理入职的第一天&#xff0c;遇到测试同事无奈且慌张的报出一个问题&#xff1a;拷机过程中&#xff0c;stTsp进程重启了。可能因为大家都比较忙&#xff0c;也可能因为面试过程中&#xff0c;我说自己比较喜欢解决问题。领导就让我帮忙一起看看。 呃&#xff0c;此时…

配置java8和java11以及输入version命令没反应问题

电脑重置重新安装java8和java11记录一下供自己观看 安装过程掠过我自己能看懂就行 需要记录一下 因为JDK11以后Oracle把JRE集成到了JDK中&#xff0c;在安装JDK11及更高版本的JDK时&#xff0c;默认是不会自动安装JRE的。在jdk11的安装目录下打开命令行窗口或者shift鼠标右键…