java面试题-并发关键字(Synchronized,volatile,final)
Synchronized
1.Synchronized可以作用在哪里?
Synchronized可以作用在方法、代码块、静态方法和类上。
方法
public synchronized void method(){//同步代码块
}
代码块
Object lock = new Object();
synchronized(lock){//同步代码块
}
静态方法
public static synchronized void staticMethod(){//同步代码块
}
类
Class clazz = MyClass.class;
synchronized(clazz){//同步代码块
}
2.Synchronized本质上是通过什么保证线程安全的?
synchronized关键字的底层实现是基于Java对象头(Object Header)和monitor实现的。
每个Java对象在内存中都有一个对象头,用于存储对象的元数据信息,包括对象的哈希码、锁状态标识、GC标记等。当一个线程访问被synchronized修饰的方法或代码块时,它会先尝试获取该对象的monitor(监视器)。
当一个线程成功获取对象的monitor时,该线程就可以进入临界区(Critical Section)执行同步代码块。在进入临界区之前,线程会将对象的锁状态标识设置为“locked”,表示该对象被当前线程占用,其他线程需要等待。当一个线程执行完同步代码块后,它会释放对象的monitor,同时将对象的锁状态标识设置为“unlocked”,这样其他线程就可以继续竞争该对象的锁,进入临界区执行同步代码块。
在Java 5之后,Java引入了基于锁升级的机制,即在Java对象头中添加了一个字段叫做“Mark Word”,用于记录对象的锁状态和其他信息。当一个线程在获取对象锁时,如果发现对象的锁状态是“unlocked”,则它会尝试使用CAS(Compare-And-Swap)指令将对象的锁状态改为“locked”,从而避免使用操作系统级别的互斥量(Mutex)造成的性能开销。如果CAS指令失败,那么就会使用操作系统级别的互斥量来实现锁,这时会将线程阻塞并放入对象的等待队列中。在Java 6之后,JVM还引入了偏向锁和轻量级锁机制,进一步提高了锁的性能。
总之,synchronized关键字的底层实现是基于Java对象头和monitor实现的,通过获取对象的锁来保证线程安全。随着Java虚拟机技术的不断发展,锁机制也在不断优化和升级,以提高并发性能和降低锁的开销。
3.Synchronized使得同时只有一个线程可以执行,性能比较差,有什么提升的方法?
我们可以考虑以下方法:
减小同步块的范围。尽量减小同步块的范围,只保护必要的共享资源,这样可以缩小锁的粒度,减少线程等待和上下文切换的开销。
使用局部变量替换共享变量。在多线程环境下,共享变量的访问比局部变量的访问开销更大。如果某个变量只在某个方法或代码块内部使用,那么就可以使用局部变量来代替共享变量,从而减少同步块的范围。
使用volatile关键字。volatile关键字可以保证变量的可见性和有序性,同时避免了锁的开销,因此可以在一些轻量级的同步场景中使用。
使用Lock接口。Java提供了Lock接口和其实现类ReentrantLock,可以替代synchronized关键字实现同步,Lock接口提供了更丰富的同步机制,比如支持超时和可中断等操作,同时也允许多个线程同时访问共享资源,从而提高了并发性能。
使用原子变量。Java提供了一些原子变量类,比如AtomicInteger、AtomicLong、AtomicReference等,这些变量可以实现一些基本的原子操作,避免了锁的开销,从而提高了并发性能。
4.Synchronize有什么样的缺陷? Java Lock是怎么弥补这些缺陷的?
Synchronized作为Java中最基本的同步机制,虽然使用简单,但也存在一些缺陷,主要包括以下几个方面:
性能问题:Synchronized的性能相对较低,因为它会导致线程之间频繁地竞争锁资源,从而导致上下文切换和线程阻塞等开销,影响程序的并发性能。
灵活性问题:Synchronized只支持一种锁机制,且不支持可重入、可中断、超时等操作,无法满足一些复杂的同步需求。
可见性问题:Synchronized只能保证共享变量在锁释放时的可见性,而不能保证变量的实时可见性,因此需要配合volatile关键字等其他机制来使用。
为了弥补Synchronized的这些缺陷,Java提供了Lock接口和其实现类,主要包括ReentrantLock、ReentrantReadWriteLock等。这些类通过以下几个方面来提高并发性能:
性能优化:Lock实现类可以实现更细粒度的控制,支持更灵活的加锁和解锁操作,可以避免Synchronized的性能问题。
灵活性提升:Lock接口和实现类提供了更多的同步机制,如可重入锁、读写锁等,同时也支持可中断、超时等操作,能够更好地满足各种复杂的同步需求。
可见性保障:Lock接口和实现类支持更细粒度的锁定和解锁操作,可以保证共享变量的实时可见性,避免了Synchronized的可见性问题。
公平性控制:Lock实现类可以通过构造函数参数来控制锁的公平性,从而避免线程饥饿等问题。
需要注意的是,Lock接口和实现类的使用需要手动管理锁的获取和释放,而且需要使用try...finally语句块确保锁的释放,否则可能会导致死锁等问题。此外,Lock的使用也需要注意一些细节问题,如使用tryLock()方法尽量避免死锁、使用ReentrantReadWriteLock来提高读操作的并发性能等。
5.Synchronized和Lock的对比,和选择?
Synchronized
使用简单,不需要手动加锁
支持可重入性和线程的可见性锁的释放由JVM自动管理,不容易出现死锁
Lock
支持公平锁和非公平锁,更加灵活
支持可中断性,可以避免死锁性能较好,
性能较好,在高并发场景下比Synchronized更快
在选择Synchronized和Lock时,需要根据具体的应用场景和需求进行选择。如果不需要过多的控制锁的粒度,只需要简单的锁定某个对象,那么使用Synchronized是一个不错的选择。如果需要更加灵活的锁控制、更好的性能、更好的可中断性等特性,那么可以选择Lock。同时,在使用Lock时,需要注意避免出现死锁等问题。
6.Synchronized在使用时有何注意事项?
尽量缩小锁的作用范围;
避免死锁;
不要将Synchronized作用于静态变量;
对锁的释放要及时;
避免使用String类型作为锁对象;
尽量避免在同步代码块中执行耗时的操作。
7.Synchronized修饰的方法在抛出异常时,会释放锁吗?
如果在执行Synchronized修饰的方法或代码块时抛出异常,JVM会自动将锁释放掉,以避免死锁的情况。因此,在使用Synchronized时,需要及时释放锁,以避免死锁等问题。
8.synchronized是公平锁吗?
在Java中,Synchronized锁默认情况下是非公平的锁。
9.多个线程等待同一个Synchronized锁的时候,JVM如何选择下一个获取锁的线程?
非公平锁
当有多个线程等待同一个Synchronized锁时,JVM并不会按照线程等待的先后顺序来选择下一个获取锁的线程。相反,它会通过一定的调度算法来选择下一个获取锁的线程,可能会导致某些线程一直无法获取锁,产生饥饿问题。
volatile
1.volatile关键字的作用是什么?
volatile关键字的作用是保证可见性和有序性,即保证所有线程都能看到它的最新值,禁止指令重排序优化,但不能保证原子性。
也就是说,多个线程同时修改同一个volatile变量时,可能会出现并发问题,因此,在需要保证原子性的场合,仍需要使用Synchronized或者Lock等其他机制来进行控制。
2.32位机器上共享的long和double变量的为什么要用volatile?
因为long和double两种数据类型的操作可分为高32位和低32位两部分,因此普通的long或double类型读/写可能不是原子的。
使用volatile关键字可以解决这个问题,因为volatile关键字可以保证变量的可见性和禁止指令重排,即保证一个线程修改了这个变量的值,其他线程可以立即看到这个变量的修改值,而且JVM不会对volatile变量的读写操作进行指令重排序优化,保证操作的有序性。
因此,当多个线程并发读写long和double类型的变量时,可以将其声明为volatile变量,从而保证线程安全。
3.volatile是如何实现可见性的?
volatile关键字可以保证变量的可见性,即一个线程修改了volatile变量的值,其他线程可以立即看到最新的值。实现原理是在写入volatile变量时,使用内存屏障指令将修改后的值刷新回主内存;在读取volatile变量时,使用内存屏障指令从主内存中读取最新的值。
4.volatile是如何实现有序性的?
volatile关键字可以保证变量的有序性,即对一个volatile变量的写操作和读操作都不能重排序。实现原理是在写入volatile变量时,在写操作之前插入内存屏障指令,保证在写操作完成之前,不会重排序到写操作之后的代码;在读取volatile变量时,在读操作之后插入内存屏障指令,保证在读操作完成之后,不会重排序到读操作之前的代码。这样可以保证volatile变量的读写操作按照代码的顺序执行。
5.说下volatile的应用场景?
状态标记:当一个线程修改了一个共享状态标记时,使用volatile关键字可以确保其他线程能够立即看到最新的状态,从而避免了死锁和饥饿等问题。
public class MyRunnable implements Runnable {private volatile boolean flag = true;@Overridepublic void run() {while (flag) {// do something}}public void stop() {flag = false;}
}
双重检查锁定(Double Checked Locking):当一个线程要获取一个单例对象时,使用双重检查锁定可以避免多个线程同时创建对象的问题。需要注意的是,双重检查锁定在Java 5之前是不安全的,因为对volatile关键字的实现不够完善。
public class Singleton {private static volatile Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}
}
线程通信:当多个线程之间需要进行通信时,可以使用volatile关键字保证通信的可见性和有序性,从而避免了死锁和饥饿等问题。
6.使用 volatile 必须具备的条件
变量状态不依赖于先前的状态:如果变量的值取决于先前的状态,那么使用 volatile 不能保证线程安全,需要使用其他的同步手段,如 synchronized 或 Lock。
变量不需要与其他状态变量共同参与不变约束:如果需要多个变量的状态一起满足某个不变条件,那么使用 volatile 也不能保证线程安全,需要使用其他的同步手段。
对变量的写操作不依赖于当前值:如果对变量的写操作依赖于当前值,那么使用 volatile 不能保证线程安全,需要使用其他的同步手段。
对变量的访问不需要加锁:如果需要对变量进行复合操作,例如“先检查再更新”操作,那么使用 volatile 不能保证线程安全,需要使用其他的同步手段。
final
1.所有的final修饰的字段都是编译期常量吗?
不是所有使用 final 修饰的字段都是编译期常量。在Java中,final 修饰的字段有两种类型:
编译期常量:使用 final static 修饰的字段被视为编译期常量,也就是类加载时就被初始化,并且在编译时就能确定其值。这种类型的字段可以直接使用类名进行访问,且访问速度很快,因为它们已经在编译期间被优化了。
运行期常量:使用 final 修饰的非静态字段被视为运行期常量,这意味着它们在运行时才被初始化,并且它们的值只能被赋值一次。这种类型的字段通常用于不变对象或常量池中的值。
因此,只有使用 final static 修饰的字段才是编译期常量,而不是所有使用 final 修饰的字段。
2.如何理解private所修饰的方法是隐式的final?
在Java中,使用 final 关键字修饰的方法不能被子类重写。如果在父类中使用 private 关键字修饰方法,则子类无法继承该方法,更不可能重写它。因此,对于使用 private 修饰的方法,它们默认就是隐式的 final 方法。
final 关键字的作用是让方法或变量的值在定义后不能被修改。对于私有方法而言,它们只能在本类中被调用,其他类无法调用它们,更不可能修改它们。因此,在这种情况下,使用 final 关键字并没有任何实际作用。
举个例子,假设有以下父类:
public class Parent {private void doSomething() {// ...}
}
如果在子类中定义了一个同名的私有方法:
public class Child extends Parent {private void doSomething() {// ...}
}
则这个子类方法并不是对父类方法的重写,而是一个新定义的私有方法。这意味着,无论父类中的方法是否使用 final 关键字,子类都无法对其进行重写。
3.说说final类型的类如何拓展?
使用 final 修饰的类是不能被继承的,所以不能直接拓展。但是可以使用以下方式来实现拓展:
以下是使用包装器类的示例代码,假设有一个 final 类 MyFinalClass:
public final class MyFinalClass {private final int value;public MyFinalClass(int value) {this.value = value;}public int getValue() {return value;}
}
然后可以创建一个包装器类 MyWrapperClass,并在其中添加一些额外的方法或属性:
public class MyWrapperClass {private final MyFinalClass myFinalClass;public MyWrapperClass(MyFinalClass myFinalClass) {this.myFinalClass = myFinalClass;}public int getValue() {return myFinalClass.getValue();}public String getDescription() {return "This is a wrapper class for MyFinalClass";}
}
可以看到,在 MyWrapperClass 中使用了 MyFinalClass 的实例,并添加了一个 getDescription() 方法来获取包装器类的描述信息。
然后在其他类中,可以使用 MyWrapperClass 来访问 MyFinalClass 的实例,并使用包装器类的额外方法或属性:
MyFinalClass finalInstance = new MyFinalClass(10);
MyWrapperClass wrapperInstance = new MyWrapperClass(finalInstance);
int value = wrapperInstance.getValue(); // 10
String description = wrapperInstance.getDescription(); // "This is a wrapper class for MyFinalClass"
通过这种方式,可以在不继承 MyFinalClass 的情况下,使用包装器类来拓展 MyFinalClass 的功能。
4.final方法可以被重载吗?
是的,final修饰的方法可以被重载,但不能被子类重写。
当子类中声明了一个和父类中同名、同参数列表、同返回类型的方法时,这个方法被称为重载方法。重载方法可以在子类中提供新的实现,但是不能改变父类中 final 方法的行为。
以下是一个示例,其中父类中有一个 final 方法 printMessage(),子类中定义了一个重载方法 printMessage(String message):
public class Parent {public final void printMessage() {System.out.println("Hello, world!");}
}public class Child extends Parent {public void printMessage(String message) {System.out.println("Hello, " + message + "!");}
}
在上面的例子中,Child 类中的 printMessage(String message) 方法是一个重载方法,不会覆盖父类中的 printMessage() 方法。如果尝试在子类中定义一个与父类中的 printMessage() 方法相同的方法,则会编译错误。
5.说说基本类型的final域重排序规则?
在Java语言中,对于基本类型的final域,JVM会禁止对它们的重排序,确保在对象发布之后,该域的值对所有线程可见,因此满足了可见性和有序性。
具体来说,对于final域的写入,JVM会在构造函数执行期间将其初始值写入该域,并将构造函数的return指令之前的所有写操作刷新到主内存中,这样,其他线程在获取该域的值时,就能读到这个最终的值。
同时,由于JVM不允许对final域进行重排序,因此在使用final域时,程序员也不需要担心其可能被重排序从而破坏线程安全。
6.说说final的原理?
在Java中,final关键字可以用来修饰变量、方法和类。对于变量,final保证了变量只被赋值一次,也就是说,final变量的值在赋值后不可更改。这个特性可以通过内存屏障来实现。在写final变量的时候,JVM会在写操作之前插入一个StoreStore屏障,保证该写操作不会被重排到屏障之后。在读final变量的时候,JVM会在读操作之后插入一个LoadLoad屏障,保证该读操作不会被重排到屏障之前。
对于方法和类,final关键字可以用来禁止子类重写方法和继承类。这个特性可以通过在编译期生成类文件时进行优化实现。如果一个类被声明为final,那么编译器会在编译时对该类的所有方法进行静态绑定(static binding),也就是在编译期就确定方法的调用方式,而不需要在运行时进行动态绑定(dynamic binding)。这样,就可以避免在运行时进行虚方法表(virtual method table)的查找,提高程序的执行效率。
总的来说,final的原理是通过内存屏障和编译器优化来实现的,保证了final变量的值只被赋值一次,以及final方法和类的不可更改性和继承性。
相关文章:
java面试题-并发关键字(Synchronized,volatile,final)
Synchronized1.Synchronized可以作用在哪里?Synchronized可以作用在方法、代码块、静态方法和类上。方法public synchronized void method(){//同步代码块 }代码块Object lock new Object(); synchronized(lock){//同步代码块 }静态方法public static synchronized void stat…...

【笔试强训】Day_02
目录 一、选择题 1、 2、 3、 4、 5、 6、 7、 8、 9、 10、 二、编程题 1、排序子序列 2、倒置字符串 一、选择题 1、 使用printf函数打印一个double类型的数据,要求:输出为10进制,输出左对齐30个字符,4位精度。…...

DepGraph:适用任何结构的剪枝
文章目录摘要1、简介2、相关工作3、方法3.1、神经网络中的依赖关系3.2、依赖关系图3.3、使用依赖图剪枝4、实验4.1、设置。4.2、CIFAR的结果4.3、消融实验4.4、适用任何结构剪枝5、结论摘要 论文链接:https://arxiv.org/abs/2301.12900 源码:https://gi…...

【结构体版】通讯录
👦个人主页:Weraphael ✍🏻作者简介:目前是C语言学习者 ✈️专栏:项目 🐋 希望大家多多支持,咱一起进步!😁 如果文章对你有帮助的话 欢迎 评论💬 点赞&#x…...
Debezium系列之:基于debezium采集数据到kafka,再从kafka将数据流式传输到下游数据库
Debezium系列之:基于debezium采集数据到kafka,再从kafka将数据流式传输到下游数据库 一、需求背景二、准备Debezium集群和相关jar包的详细步骤三、查看插件是否加载成功四、源数据库表结构五、根据源数据库表结构准备目标数据库的表六、基于debezium采集数据到kafka七、查看c…...
【2023】华为OD机试真题Java-题目0217-上班之路
上班之路 题目描述 Jungle生活在美丽的蓝鲸城,大马路都是方方正正,但是每天马路的封闭情况都不一样。 地图由以下元素组成: . — 空地,可以达到;* — 路障,不可达到;S — Jungle的家;T — 公司. 其中我们会限制Jungle拐弯的次数,同时Jungle可以清除给定个数的路障,现在…...
基于spring生态的基础后端开发及渗透测试流程(二)
基于spring生态的基础后端开发及渗透测试流程(二)安全设备IDS蜜罐安全加固渗透测试信息收集子域名域名注册信息企业信息端口扫描源码泄露路径扫描真实ip探测js扫描设备检测蜜罐识别waf识别社工爆破漏洞扫描系统扫描web扫描应急响应继上次写了一份基于spr…...
Python语言零基础入门教程(二十六)
Python OS 文件/目录方法 Python语言零基础入门教程(二十五) 51、Python os.stat_float_times() 方法 概述 os.stat_float_times() 方法用于决定stat_result是否以float对象显示时间戳。 语法 stat_float_times()方法语法格式如下: os.s…...

人们最想看到的是:你在坚持什么?
【人们最想看到的是:你在坚持什么】 长远规划才能对抗不确定性 品牌也能够对抗不确定性 想想这么多年东搞搞,西搞搞 最后缺乏正向积累的【厚度】 趣讲大白话:把每滴水尽量接到碗里 人吃的是饭,拉出来的是信息 *********** 人们在频…...

300行代码手写spring初体验v1.0版本
70%猜想30%验证 spring:IOC 、DI、AOP、MVC MVC作为入口 web.xml 内部依赖一个DispathcheServlet这样一个接口 先来说一下springMVC的一些基础知识 整体的一个思路: 在web.xml里面进行了一个核心servlet的一个配置 核心就是这个DispatcherServlet …...

100天精通Python(数据分析篇)——第76天:Pandas数据类型转换函数pd.to_numeric(参数说明+实战案例)
文章目录专栏导读一、to_numeric参数说明0. 介绍1. arg1)接收列表2)接收一维数组3)接收Series对象2. errors1)errorscoerce2)errors ignore3. downcast1)downcastinteger2)downcastsigned3&…...

链表(超详细--包教包会)
目录 一、概述 二、对链表的基本操作 三、链表的分类 四、静态链表 五、动态链表 1、malloc函数 2、calloc函数 3、free函数 六、动态链表的建立 七、输出链表中的数据 八、查找节点 九、删除节点 十、插入节点 十一、整体代码 一、概述 链表存储结构是一种动态数据…...

爬虫基本知识的认知(爬虫流程 HTTP构建)| 爬虫理论课,附赠三体案例
爬虫是指通过程序自动化地从互联网上获取数据的过程。 基本的爬虫流程可以概括为以下几个步骤: 发送 HTTP 请求:通过 HTTP 协议向指定的 URL 发送请求,获取对应的 HTML 页面。解析 HTML 页面:使用 HTML 解析器对获取的 HTML 页面…...

Ubuntu20.04如何安装虚拟机(并安装Android)
安装虚拟机(KVM)这种KVM只能安装windows无法安装安卓(From https://phoenixnap.com/kb/ubuntu-install-kvm)A type 2 hypervisor enables users to run isolated instances of other operating systems inside a host system. As a Linux based OS, Ubun…...
【腾讯一面】我对我的Java基础不自信了
我对我的Java基础不自信了1、List和set的区别?2、HashSet 是如何保证不重复的3、HashMap是线程安全的吗,为什么不是线程安全的?4、HashMap的扩容过程5、Java获取反射的三种方法6、Redis持久化机制原理7、redis持久化的方式各有哪些优缺点1、L…...

前端都在聊什么 - 第 2 期
Hello 小伙伴们早上、中午、下午、晚上、深夜好,我是爱折腾的 jsliang~「前端都在聊什么」是 jsliang 日常写文章/做视频/玩直播过程中,小伙伴们的提问以及我的解疑整理。本期对应 2023 年的 01.16-01.31 这个时间段。本期针对「规划」「工作」「学习」「…...

每天一道大厂SQL题【Day11】微众银行真题实战(一)
每天一道大厂SQL题【Day11】微众银行真题实战(一) 大家好,我是Maynor。相信大家和我一样,都有一个大厂梦,作为一名资深大数据选手,深知SQL重要性,接下来我准备用100天时间,基于大数据岗面试中的经典SQL题&…...
Cosmos 基础教程(一) -- 不可不知的开发术语
CometBFT DOC 您可以在本节中找到几个技术术语的概述,包括每个术语的解释和进一步资源的链接——在使用Cosmos SDK进行开发时,所有这些都是必不可少的。 在本节中,您将了解以下术语: Cosmos and Interchain LCD RPC Protobuf -协议缓冲…...

JAVA JDK 常用工具类和工具方法
目录 Pair与Triple Lists.partition-将一个大集合分成若干 List集合操作的轮子 对象工具Objects 与ObjectUtils 字符串工具 MapUtils Assert断言 switch语句 三目表达式 IOUtils MultiValueMap MultiMap JAVA各个时间类型的转换(LocalDate与Date类型&a…...

Spring Bean循环依赖
解决SpringBean循环依赖为什么需要3级缓存?回答:1级Map保存单例bean。2级Map 为了保证产生循环引用问题时,每次查询早期引用对象,都拿到同一个对象。3级Map保存ObjectFactory对象。数据结构1级Map singletonObjects2级Map earlySi…...

【Axure高保真原型】引导弹窗
今天和大家中分享引导弹窗的原型模板,载入页面后,会显示引导弹窗,适用于引导用户使用页面,点击完成后,会显示下一个引导弹窗,直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...

JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...

前端开发者常用网站
Can I use网站:一个查询网页技术兼容性的网站 一个查询网页技术兼容性的网站Can I use:Can I use... Support tables for HTML5, CSS3, etc (查询浏览器对HTML5的支持情况) 权威网站:MDN JavaScript权威网站:JavaScript | MDN...

Matlab实现任意伪彩色图像可视化显示
Matlab实现任意伪彩色图像可视化显示 1、灰度原始图像2、RGB彩色原始图像 在科研研究中,如何展示好看的实验结果图像非常重要!!! 1、灰度原始图像 灰度图像每个像素点只有一个数值,代表该点的亮度(或…...

Linux基础开发工具——vim工具
文章目录 vim工具什么是vimvim的多模式和使用vim的基础模式vim的三种基础模式三种模式的初步了解 常用模式的详细讲解插入模式命令模式模式转化光标的移动文本的编辑 底行模式替换模式视图模式总结 使用vim的小技巧vim的配置(了解) vim工具 本文章仍然是继续讲解Linux系统下的…...

生信服务器 | 做生信为什么推荐使用Linux服务器?
原文链接:生信服务器 | 做生信为什么推荐使用Linux服务器? 一、 做生信为什么推荐使用服务器? 大家好,我是小杜。在做生信分析的同学,或是将接触学习生信分析的同学,<font style"color:rgb(53, 1…...