Java基础

Java语言是一种分布式的面向对象语言,具有面向对象、平台无关性、简单性、解释执行、多线程、安全性等多个特点。

JDK,Java标准的开发包,提供了编译、运行Java程序所需要的各种资源和工具,包括Java编译器、Java类库、Java运行时环境。

JRE,Java运行时环境,用于解释执行Java的字节码文件。普通用户只需要安装JRE就可以运行Java程序,程序员还需要另行安装JDK编译、调试程序。

JVM,Java虚拟机,是JRE的一部分。它是整个Java实施跨平台的核心,负责解释执行字节码文件,是可运行Java字节码文件的虚拟机。

JVM主要组成部分?作用?

  • 类加载器

  • 运行时数据区

  • 执行引擎

  • 本地库接口

首先通过类加载器会把Java代码转换为字节码,运行时数据区再把字节码加载到内存中,而字节码只是JVM的一套指令集规范,并不能直接交给底层操作系统去执行,因此需要特定的命令解析器执行引擎,将字节码翻译成底层系统指令,再交给CPU执行,在这个过程中需要调用其他语言的本地库接口来实现整个程序的功能。

==和equals的区别:

对于基本类型和引用类型==的作用是不同的,基本类型比较值是否相同,引用类型则是比较引用是否相同。而equals只能比较对象,不能比较基本类型。

方法重载和重写的区别:

重载在一个类里面方法名相同,参数不同的两个方法;

重写是在不同类里面的而且必须是集成关系,返回值类型和参数必须相同。

Java中操作字符串都有哪些类?区别又是什么:

操作字符串的类有:String、StringBuffer、StringBuild

String和StringBuffer、StringBuild的区别在于String声明的是对象,每次操作都会生成一个全新的对象,然后指针指向新的String对象;StringBuffer、StringBuild可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不使用String。

StringBuffer是线程安全的,因为Buffer用了Synchronized进行修饰,而StringBuild则是线程不安全的,所以多线程Buffer单Build。

Java中的IO流:

按功能区分:输入流、输出流

按类型区分:字节流、字符流

字节流和字符流的区别在于,字节流按8位传输以字节为单位输入输出数据,字符流按照16位传输以字符为单位输入输出。

ArrayList和LinkedList的区别:

Array是基于数组实现的,而Linked则是基于链表实现;

对于随机访问,Array要高于Linked;对于插入和删除,Linked要高于Array;

Linked比Array更加占内存,因为Linked的节点除了存储数据,还存储了两个引用,一个指向前一个元素一个指向后一个元素。

实现数组和List之间的转化:

数组转List:使用Arrays.asList(array)进行转换;

List转数组:使用List自带的toArray()方法。

哪些集合类是线程安全的?

只有Vector、HashTable、Properties是线程安全,但是在JDK1.5后Java.util.concurrent的出现,HashMap等线程不安全的集合类也有相对应的线程安全类ConcurrentHashMap。

线程的定义:

线程是操作系统所能进行运算调度的最小单位,它被包含在进程当中,是进程中实际运作单位,可以使用多线程对运算提速。线程数量与需要时间成反比。

线程的状态:

  • NEW    尚未启动、

  • RUNNABLE    正在执行中、

  • BLOCKED    阻塞的、

  • WAITING    等待中、

  • TIMED_WAITING    等待指定的时间重新被唤醒、

  • TERMINATED    执行完成

并发和并行的区别:

并发:多个任务在同一个CPU上,按照细分的时间片段轮流交替执行

并行:单位时间内,多个处理器或者多核处理器同时处理多个任务

创建线程的四种方式:

继承Thread类、实现Runnable接口、实现Callable接口、Executors工具类创建线程池

线程安全和线程不安全:

线程安全,多线程访问时,对其进行加锁,当一个线程访问该类的某个数据时,进行保护,其他线程就不能再进行访问,直到该线程完成访问后,其他线程才可以使用。不会出现数据不一致或数据污染。

线程不安全,不提供数据访问保护,又可能出现多个线程先后更改数据造成所得到的数据是脏数据,线程安全问题都是由全局变量及静态变量引起的。如果每个线程中对全局变量、静态变量只有读操作,而没有写操作,这个全局变量暂时是安全的;如果多个线程同时执行进行写的操作,一般都要考虑线程同步。

Sleep()和Wait()的区别:

类不同:sleep()来自Thread,wait()来自Object。

释放锁:sleep()不释放锁,wait()释放锁。

用法不同:sleep()时间到会自动恢复,wait()则需要notify()/notifyAll()直接唤醒。

notify()和notifyAll()区别:

notifyAll唤醒所有的线程,notify唤醒一个线程。

All调用后,会将全部线程由等待池移到锁池,然后参与锁的竞争,竞争成功则继续执行,如果不成功则留在锁池等待锁被释放后再次参与竞争。

run()和start()区别:

start()方法用于启动线程,run()用于执行线程的运行时代码。run可以重复调用,start只能调用一次。

死锁:

死锁是两个或两个以上的进程在执行过程当中,由于竞争资源或者由于彼此通信而造成一种阻塞的现象,如果无外力作用,它们都将无法推进下去。此时系统处于死锁状态,这些永远都在互相等待的进程称为死锁进程。操作系统层面的错误。

死锁的四个必要条件:

  • 互斥条件:进程对所分配的资源不允许其他进程进行访问,若其他进程访问该资源,只能等待,直到占有该资源的进程使用完成后释放该资源。

  • 请求和保持条件:进程获得一定的资源之后,又对其他资源发出请求,但是该资源可能被其他进程占有,此时请求阻塞,但自己所获得资源迟迟不肯放手

  • 不可剥夺条件:是指进程已获得资源,在未完成使用之前,不可被剥夺,只能在使用后完成自己的释放。

  • 环路等待条件:进程发生死锁后,若干进程之间形成一种头尾相接的循环等待资源关系

Java序列化:

Java序列化是为了保存各种对象在内存中的状态,并且可以保存的对象状态再读出来。

需要将内存中的对象状态保存到一个文件当中或者数据库当中的时候;

需要套接字在网络上传送对象的时候;

想通过RMI(远程方法调用)传输对象的时候。

Session工作原理:

session的工作原理是客户端登录完成后,服务器会创建对应的session,session创建完之后,会把session的id发送给客户端,客户端再存储到浏览器当中。这样的客户端每次访问服务器时,都会带者sessionId,服务器拿到sessionId后,在内存找到与之对应的session这样就可以正常工作。

Session和Cookie区别:

cookie数据保存在客户端,session数据保存在服务端;

cookie数据存放在客户的浏览器上,session数据放在服务器上;

session和cookie更具有安全性;

session占用服务器性能,session过多,增加服务器压力;

单个cookie保存的数据不能超过4k,很多浏览器都限制一个站点最多保存20个cookie,session没有大小限制只与服务器内存大小有关。

如果客户端禁止cookie,session还能使用吗?

可以,session只是依赖cookie存储sessionId,如果cookie被禁用了,可以使用url中添加sessionid的方式保证session能正常使用。

final在java中有什么作用?

final修饰的类称为最终类,此类不能被继承。

final修饰的方法不能被重写。

final修饰的变量叫做常量,常量必须初始化,初始化之后值就不能被修改。

tcp与udp区别:

TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发生数据之前不需要建立连接。

TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按顺序到达;UDP尽最大努力交付,即不保证可靠交付。

TCP通过校验,重传控制,序号标识,滑动窗口,确认应答实现可靠传输。如丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。

UDP有较好的实时性,工作效率比TCP高,适用于高速传输和实时性有较高的通信或广播通信。

每一条TCP连接只能是点到点;UDP支持一对一,一对多,多对一和多对多的交互通信。

TCP对系统资源要求较多,UDP对系统资源要求较少。

反射的定义:

反射是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法功能称为Java语言的反色机制。

Mybatis中#{}和${}区别:

#{}是预编译,可以防止SQL语句注入;${}则是拼接符号。

Spring:

ioc,容器会帮组管理依赖的对象,不需要自己创建和管理依赖对象,更轻松的实现了程序的解耦。

事务支持,事务操作更加方便。

aop,通过预编译方式和运行期动态代理实现程序功能的统一维护。简单来说就是,统一处理某一“切面”(类)的问题的编程思想,比如统一处理日志、异常等。

更加方便的框架集成,spring可以很方便的处理集成其他框架,比如MyBatis。

SpringMVC组件:

  • DispatcherServler    前置控制器;

  • HandlerMapping    映射控制器;

  • Controller    处理器;

  • ModelAndView    模型和视图;

  • ViewResolver    视图解析器。

@RequestMapping的作用:

将http请求映射到相应的类/方法上。

SpringBoot:

配置简单,独立运行,自动专配,无代码生成和xml配置,提供应用监控

SpringBoot的核心配置文件:

bootstrap:bootstrap由父ApplicationContext加载的,比application优先加载,且bootstrap属性不能被覆盖。

application:用于SpringBoot项目的自动化配置。

SpringCloud:

springCloud是一系列框架的有序集合。它利用springboot的开发便利性巧妙简化了分布式系统的基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring boot的开发风格做到一键启动和部署。

SpringCloud断路器:

在分布式架构中,断路器模式的作用也是差不多的,当某个服务单元发生故障(类似用电器发生短路)后,通过断路器的故障监控(类似熔断保险丝),向调用方法返回一个错误响应,而不是长时间的等待。这样就不会使得线程因调用故障服务被长时间占用不释放,避免了故障在分布式系统中的蔓延。

SpringCloud核心组件:

Eureka:服务注册于发现。

Feign:基于动态代理机制,根据注解和选择的机器,拼接请求url地址,发送请求。

Ribbon:实现负载均衡,从一个服务的多台机器中选择一台。

Hystrix:提供线程池,不同的服务走不同的线程池,实现了不同服务调用的隔离,避免了服务雪崩的问题。

Zuul:网关管理,由Zuul网关转发请求给对应的服务。

Mybatis的一级缓存和二级缓存:

一级缓存,基于PerpetualCache的HashMap本地缓存,它的声明周期是和SQLSession一致的,有多个SQLSession或者分布式环境中数据库操作,可能会出现脏数据。当Session flush或者close之后,该session中的所有Cache就将清空,默认一级缓存是开启的。

二级缓存,同样是基于HashMap的本地缓存,不同在于其存储作用域为Mapper级别的,如果多个SQLSession之间需要共享缓存,则需要使用到二级缓存,并且二级缓存可自定义存储源,,如Ehcache。默认不打

开启二级缓存数据查询流程:二级缓存->一级缓存->数据库。

缓存更新机制:当某一个作用域(一级缓存Session/二级缓存Mapper)进行了C/U/D操作后,默认该作用域下所有select中的缓存将被clear。

RabbitMQ使用场景:

抢购活动,削峰填谷,防止系统崩溃

延迟信息处理,比如10分钟后给下单未支付的用户发送提醒信息。

解耦系统,对于新增的功能可以单独写模块扩展比如用户确认评价之后,新增了给用户返积分的功能,这个时候不用业务代码里添加新增积分的功能,只需要把新增积分的接口订阅确认评价的消息队列即可,后面再添加任何功能只需要订阅对应的消息队列即可。

RabbitMQ重要角色:

生产者,消费者和代理。

生产者:消息的创建者,负责创建和推送数据到消息服务器。

消费者:消息的接收方,用于处理数据和确认消息。

代理:就是RabbitMQ本身,用于扮演“快递”的角色,本身并不生产消息,只是扮演“快递”的角色。

RabbitMQ重要组件:

ConnectionFactory(连接管理器):应用程序与Rabbit之间建立连接的管理器,程序代码中使用。

Channel(信道):消息推送使用的通道。

Exchange(交换器):用于接送、分配消息。

Queue(队列):用于存储生产者的消息。

RoutingKey(路由键):用于把生产者的数据分配到交换器上。

Bindingkey(帮顶键):用于交换器的消息绑定到队列上。

RabbitMQ中的vhost:

每个RabbitMQ都能创建很多vhost,称之为虚拟主机,每个虚拟主机其实都是mini版的RabbitMQ,它拥有自己的队列,交换器和绑定,拥有自己权限机制。

RabbitMQ消息是怎么发送的:

客户端必须连接到RabbitMQ服务器才能发布和消费信息,客户端和rabbit server之间会创建一个tcp连接,一旦tcp打开并通过了认证(发送给rabbit服务器的用户名和密码),客户端和rabbitmq就创建了一条amqp信道(channel),信道是创建在真实tcp上的虚拟连接,amqp命令都是通过信道发送出去的,每个信道都会有一个唯一的id,不论是发布消息,订阅队列都是通过这个信道完成的。

RabbitMq怎么保证消息的稳定性:

ACID的功能。

将Channel设置为confirm确认模式。

RabbitMq怎么避免消息丢失?

把消息持久化到磁盘当中。每个集群当中至少有一个物理磁盘,保证消息落入磁盘。

要保证消息持久化成功的条件有哪些?

声明队列必须设置持久化durable设置为true。

消息推送投递模式必须设置持久化,deliveryMode设置为2(持久)。

消息已经到达持久化交换器。

消息已经到达持久化队列。

rabbitmq持久化的缺点:

持久化降低了服务器的吞吐量,因为使用的磁盘而非内存。可以尽量使用ssd硬盘环节吞吐量的问题。

rabbitmq怎么实现延迟消息队列:

通过消息过期后进入死信交换器,再由交换器转发到延迟消费队列,实现延迟功能;

使用RabbitMQ-delayed-meaagae-exchange插件实现延迟功能。

RabbitMQ集群:

高可用:某个服务器出现问题,整个RabbitMQ还可以继续使用;

高容量:集群可以承载更多的消息量。

RabbitMQ节点的类型?

磁盘节点:消息会存储到磁盘。

内存节点:消息会存储在内存中,重启服务器消息丢失,性能高于磁盘类型。

RabbitMQ集群搭建需要注意哪些问题?

各个节点之间使用“—link”连接;各个节点使用的relang cookie值必须相同,此值相当于“秘钥”的功能,用于各节点的认证。

整个集群中必须包换一个磁盘节点。

zookeeper:

zookeeper是一个分布式,开放源码的分布式应用程序协调服务,是hadoop和hbase的重要组件。是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。

zookeeper有哪些功能?

集群管理:监控节点存活状态、运行请求等。

主节点选举:主节点死了后可以从备用的节点开始新一轮选主,主节点选举说的就是这个选举的过程,使用zookeeper可以协助完成这个过程。

分布式锁:zookeeper提供两种锁:独占锁、共享锁。独占锁即一次只能有一个线程使用资源,共享锁是读锁共享,读写互斥,即可以有多线程同时读一个资源,如果要使用写锁也只能有一个线程使用。zookeeper可以对分布式锁进行控制。

命名服务:在分布式系统中,通过使用命名服务,客户端应用能够根据指定名字来获取资源或服务的地址,提供者等信息。

zookeeper的三种部署方式:

单机部署(一台集群上运行)、集群部署(多台集群运行)、伪集群部署(一台集群启动多个zookeeper实列运行)

zookeeper怎么保证主从节点的状态同步?

zookeeper的核心是原子广播,这个机制保证了各个server之间的同步。实现这个机制的协议叫做zab协议。

zab协议有两种模式:恢复模式(选主)和广播模式(同步)

当服务启动或者在领导者崩溃后,zab就进入了恢复模式,当领导者被选举出来后,且大多数server完成了和leader状态同步后,恢复模式就结束了。状态同步保证了leader和server具有相同的系统状态。

MySQL内连接、左连接、右连接区别:

inner join、left join、right join

内连接是把匹配的关联数据显示出来;左连接是左边的表全部显示,右边的表显示出符合条件的数据;右连接正好跟左连接相反。

MySQL索引实现:

索引是满足某种特定查找算法的数据结构,而这些数据结构会以某种方式指向数据,从而实现搞笑查找数据。

具体来说MySQL的所有,不同的数据引擎实现有所不同,但目前主流的数据库引擎都是B+树实现的,B+树的搜索效率,可以到达二分法的性能,找到数据区域之后就找到了完整的数据结构,所有的索引性能也是更好的。

Redis功能:

数据缓存、分布式锁、数据持久化、支持事务、支持消息队列

Redis怎么实现分布式锁?

redis分布式锁其实就是在系统里面占一个茅坑,其他程序也要占茅坑的时候,占用成立就继续执行,失败了从头来过。占坑一般使用setnx指令,只允许被一个程序占有,使用完调用del释放锁。

Redis分布式锁缺陷:

Redis分布式锁不能解决超时的问题,分布式锁有一个超时时间,程序的执行如果超出了锁的超过时间就会出现问题。

将set指令的value参数设置一个随机数,释放锁先匹配随机数是否一致,然后再删除key,这是为了确保当前线程占有的锁不会被其他线程释放,除非这个锁是自动超时,但是匹配value和删除key不是一个原子操作。

Redis内存优化:

尽量使用Redis的散列表,把相关的信息放到散列表里面进行存储,而不是把每个字段单独存储,这样可以有效减少内存的使用。比如将Web系统的用户对象,应该放到散列表里面再整体存储到Redis,而不是把童用户的姓名、年龄、密码、邮箱等字段分别设置key存储。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值