不是前言的前言 个人日常

目录

Spring AOP的术语

Join point(连接点)

程序中执行过程中的一个点,如方法的执行或者异常的处理,在SpringAOP中,连接点总是表示方法的执行,通俗的讲,连接点即表示类里面可以增强的方法。

Pointcut(切入点)

切入点是与连接点匹配的表达式,用于确定是否需要执行通知。切入点使用与连接点匹配的不同类型的表达式,Spring框架使用AspectJ切入点表达式语言,我们可以将切入点理解为需要拦截的Join point。

Advice(增强/通知)

所谓通知是指拦截到Join point之后要做的事情就是通知,分为前置通知与后置通知,异常通知与最终通知,环绕通知。

Aspect(切面)

Aspect切面表示Pointcut和Adcvice的结合。

动态代理的两种模式

是cglib和jdk两个不同的方式。

cglib(code generation library)

cglib不能代理用final修饰的类,因为他的本质是代理cglib生成的子类(字节码)从而实现动态代理。

jdk

jdk涉及的是Proxy与InvocationHandler两个类,jdk的本质是代理接口,所以可以看到代理的参数,有一个借口的数组。

使用细节

Spring默认采取jdk动态代理来完成操作,如果被代理的对象是一个实现类。
如果不是实现类,那么采用CGLib来实现动态代理。但是SpringBoot修改成了CGLib是默认的代理模式。

或者在spring中的proxy-target-class中的属性,true为cglib,false为jdk。

两者对比

cglib运行的速度比jdk的快,但是没有jdk创建代理实现类快。

线程池的核心线程数

在这里插入图片描述

Ncpu为核心线程数,Ucpu为线程使用率,等待时间w与计算时间c

io密集型

一般情况下,w阻塞耗时一般都是c计算耗时的很多倍,但是考虑到系统内存有限,每开启一个线程都需要内存空间,这里需要上服务器测试具体多少个线程数适合。通常来说,设置为2Ncpu即可。

计算密集

相当于w阻塞时间为0,那么就是Ncpu

JMM中的压缩指针

压缩指针的实现,实质上不再保存所有的引用,而是每隔8个字节保存一个引用。主要压缩了对象头的kclass指针引用的大小,从而减少了字节。

开启UseCompressedOops

信息被压缩程度

对象头信息:klass会从8字节,压缩成为4字节,MarkDown不会变
对象引用类型:从8字节,压缩成为4字节
对象数组类型:从24字节,压缩成为16字节

代码的执行流程

从计算机软件层次

首先,我利用idea编译器编写java代码,java通过jvm编译生成.class字节码文件。然后加载到jvm中,通过jvm解析成为机器语言,从而通过机器语言操作操作系统。操作系统底层操作硬件来执行每条语句。

从硬件层面分析底层

首先控制器pc(程序计数器)向mar(地址寄存器)发送指令,mar向内存中获取要执行的指令,在从mdr(变量寄存器)中获取存储的数据。然后一起放到cpu中的ir(指令寄存器),最后传给cu(控制单元),控制器传给运算器,运算器进行对变量的计算,然后将最后的结果返回给内存中。

缓存一致性协议 MESI

分别是modified/exclusive/shared/invalid

modified

表示cpu进行了写的操作,并且表示当前写的元素不会存在再其他缓存中。说明当前这个数据是该cpu独占的。写完之后,将该数据传给其他的cpu或者memory主存当中。

exclusive

与modified相同,cpu独占该cache line,可以直接修改不用通知其他的cpu。因为memory和其他的数据都是最新的。

shared

数据存在与多个cpu中,cpu不可以直接修改cache line的值,需要通知其他cpu。

invalid

无效的,当前的cache line是空的,

数据库中的锁

行锁

共享锁(s)

排他锁(x)

表锁

意向锁

意向锁同也分为共享锁与排他锁。意向锁的作用是为了提高效率,比如A如果在表中上了表中写锁的,此时B想要在表中某一行加锁,那么他首先先看整个表是否被加了意向锁,再根据意向锁获取到前面锁的位置,看是否冲突,如果冲突阻塞住,不冲突进行加锁。

这样节省了效率,如果没有意向锁,B想要加锁的时候就需要遍历整个表,看是否有锁。
在这里插入图片描述

Mysql的多版本控制

快照读

多版本并发控制MVCC,是行级锁的变种版本。通过保存数据在事务开启的快照,由此不同事务对应同一张表,同一时刻可能看到的数据是不一样的。在表中数据行的后面加上了创建日期版本号和删除日期版本号,且版本号不断递增,实现了数据快照。

RR与RC关于可重复度

其实就如同上面上面所说的一样,每次开启的时候都会生成快照,称为ReadView,RR是在事务开启的时候,RV就已经生成了,并且不会在改动。而RC是在每次进行操作的时候的,重新获取RV。

当前读

当前读是通过间隙锁来实现的。Record-lock单行锁,Gap-lock,间隙锁,锁定一个范围,但是不包括本身。

Next-key Lock是上面record-lock与gap-lock的结合,锁定一个范围,索引之间的间隙,并且锁定记录本身。

当前读的实现方式

除了update,delete,create。
在select中, FOR UPDATE (加写锁) LOCK IN SHARE MODE(加读锁)
当前读就会加next-key lock

进程调度算法

先来先到
短作业/剩余短作业
时间片轮转
多级反馈队列

磁盘调度算法

先来先去
最短寻道时间
电梯算法

线程间通信方式

互斥量Sychronized/lock

采用互斥对象机制,只有拥有互斥对象才可以访问公共资源。因为互斥对象只有一个,可以保证公共资源同时只有一个线程在执行。

信号量

事件wait/notify

允许一个线程在处理完,通知另一个线程开始运行。

进程间通信方式

管道 命名管道 匿名管道
消息队列
信号量
共享内存
远程调度socket

序列化

当我们远程发送文件的时候,都是将文件转换为字节流进行传输。
序列化就是将java对象转换成字节序列的方式
反序列化就是将字节序列转换成java对象

序列化的方式

继承Serializable 或者Externalizable接口(要求有默认的构造函数),有一个UUID用来标识序列和反序列化。

实现序列化

         ObjectOutputStream采用默认的序列化方式,对Student对象的非transient的实例变量进行序列化。 
         ObjcetInputStream采用默认的反序列化方式,对Student对象的非transient的实例变量进行反序列化。

cookie与session

cookie实际上是请求体的一个字段。

cookie的安全性

域名不同,不能使用同一个cookie

session

session是记录客户状态的i机制,不同于cookie保存在客户端,而session保存在服务器上。

禁用cookie,如何使用session

URL地址重写是对客户端不支持Cookie的解决方案。URL地址重写的原理是将该用户Session的id信息重写到URL地址中。服务器能够解析重写后的URL获取Session的id。这样即使客户端不支持Cookie,也可以使用Session来记录用户状态。

Mysql的持久化技术

对比redo log 与bin log

redo log是物理页面,实际上表结构进行了怎样的变化。而bin log记录的是进行了什么操作,update,create ,delete。
redo log是innoDB特有的,bin log是所有的引擎都有的。
redo log是循环写的问题,一组4个文件,一个文件1GB,可以重复使用。
bin log是要持久化的永久的记录下来的。

mysql的写入机制

innodb_flush_log_at_trx_commit 0 1 2
0 n秒写入redo log文件,再将文件刷入磁盘
1 每个事务提交的时候,先写缓存,在写内存,最后写磁盘。
2 每个事务提交的时候,写内存,何时入磁盘由操作系统决定。

redo log和bin log的一致性

mysql引入两阶段提交2pc,mysql每一个普通的事务都会转换成一个xa事务。
prepare阶段,产生了xid,redo log 和undo log内存已经写入了。在调用prepare将redo log刷入磁盘。
commit阶段,write方法,将bin log内存写入缓存,fsync将缓存永久写入磁盘,最后调用commit。

达到了如果已经commit数据仍然存在,没有提交的数据进行回滚。

IO

IO五种模型

同步阻塞 同步非阻塞 多路复用 信号机制 异步

BIO NIO AIO

blocking io倒是没什么好说的。
市面上的NIO的应用很多,netty和redis 都是采用nio的多路复用来实现的。

NIO的三个核心概念

缓冲区Buffer,IO面对是流,而NIO面对的是缓冲区。
通道Channel,可以通过它读取和写入数据,通过Channel读取和写入。
多路复用器Selector,监听多个Channel通道感兴趣的事情,

TCP重传机制

首先,要明白一点,有两种情况,第一种是发送的报文,接收端根本没有收到,第二种情况是接收端收到了,但是返回的ACK报文没有传送回去。

超时重传

一般设置为一个RTT,RTO是根据RTT算出来的。
超时时间过大,重发变慢,没有效率,性能差
超时时间过小,其实并没有丢包,就进行重传,于是重发的就快,导致网络阻塞。

快速重传

如果发送端,连续接受到了3相同的ACK报文,会在定时器过期重传,重传丢失的报文。

SACK

快速重传有一个问题,当接受到三个ACK的时候,是选择重传一个,还是都选择重传呢?
就有了SACK,在tcp头部选项加一个sack的东西,可以在ack的时候告知,哪一个部分的信息已经丢失。

D—SACK

sack的加强版,还告诉了发送方,有哪些数据被重复接受了。

TCP的阻塞控制

慢启动

在没有丢包的情况下,每次接受到ack,就将拥塞窗口按照指数增长,初始化的值为1,单位是MSS,最大单个报文长度。在这里插入图片描述

拥塞避免

不可能让慢启动这种按照指数一直无限的增长,一定需要某个限制。tcp使用了一个叫慢启动门限(ssthresh)的变量,通常大小是(65536),一旦拥塞窗口超过该阈值,进行到拥塞避免状态。

此时拥塞窗口不再像慢启动状态下的指数增长,每次ACK接受的时候,窗口就+1,呈线性增长。如果此时出现了丢包,那么首先把ssthresh降低为cwnd的一半,然后把拥塞窗口置为1,从新开始慢启动

快速重传

tcp在收到重传的3次ack,会认为重传的第一个报文段被网络丢弃。
把ssthresh设置为cwnd的一半
把cwnd设置为ssthresh的值,重新进入拥塞避免阶段。

快恢复

快重传进入快恢复阶段,将慢启动阈值修改为当前拥塞窗口的一半,同时拥塞窗口值等于慢启动阈值,然后重新进入拥塞避免状态。

虚拟内存

页面置换算法

FIFO 先进先出
LRU 最近最少使用算法
LFU 最少使用次数算法
OPT 最优置换算法
第二次机会算法 对fifo的算法改进
时钟

颠簸

指频繁的进行页面置换算法,进程发生缺页中断,必须置换某一页,然而,其他的页都在使用,他置换出这个页,又要马上使用这个页。

解决方法,就是调大物理内存容量,选择更合适的页面置换算法,终止该进程。

类的初始化(加载)

类的加载阶段都是由类的初始化引起的,使用的时候才会进行类的加载。

用new关键字的时候
java.lang.reflect包下面的反射机制
加载子类的时候,加载父类
使用静态成员变量和调用静态成员方法的时候
虚拟机会自动加载main方法所在的类

双亲委派机制

当进行加载类的时候,优先会让自己的父类加载器去加载类的二进制字节流,过程直到最高级父类引导类加载器(Bootstrap ClassLoader),如果父类能够加载,则加载,不能的话,再由子类来进行加载。

双亲委派机制是为了保证Java核心库的安全性,这种机制保证了用户自己能定义java.lang.Object类等的情况。

值得注意的是

双亲委派机制是代理模式的一种,但不是所有的类的加载器都采用双亲委派机制,在tomcat服务器类加载器也使用代理模式,但是它自己会主动去加载某个类,如果自己加载不了,再通过父类加载器去加载。与正常的类的加载器都反过来了。但也是为了保证安全,这样核心库就不在查询范围之内。

Linux如何设置环境变量

编辑

/etc/profile 文件
如何想要立即生效
source /etc/profile

Linux环境变量有多少个

计数

env |wc -l

海量日志数据,提取出某日访问百度次数最多的那个ip

把大文件按照hash(ip)%1000 分割成1000个小文件,相同ip的日志落在了同一个文件中,针对每一个小文件,用hashmap统计出出现次数最多的那个ip,得到1000个“最多的ip中最大最多的即可。

再详细一点结合数据来说。一天访问的ip数量不超过4亿次,找到访问次数最多的ip。
一个ip地址是32位,所以会有2*32 = 4G的不同的地址,int类型的占4字节,所以需要16G的内存。
假设使用的内存是512mb,512mb/4= 128mb,所以每次一次内存可以存128mb的大小的ip地址,4g/128 = 32,所以建立32个小区间,每次从区间中统计出来最大的ip。
2^5 = 32 ,所以,让一个ip地址右移27位,得到的数字作为编号,那么其余27位,&1就是value的值,放在tmp3的文件中,这样都分好之后,统计出每一个文件中出现次数最多的ip,再对32个ip进行比较,看哪个次数最多。即为所求。

热门查询,300w个查询字符中统计最热门的10个查询

原题:每个查询的子串的大小都是255字节,要求内存不超过10G

一个子串是255字节,10的-9次幂的g的大小,所以内存为

255*10 -9次幂 * 3 10的6次幂 = 0.75g,所以完全可以放在内存中运行,维护一个hashmap,最后再利用堆排序,构造出10个最多的查询。

有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1M。返回频数最高的100个词。

一个词是16字节,所以1K的内存可以存64个词,1g大小有64*10的6次个词。

所以将64*10的3次幂 分成一个文件,可以按照无序排列。1g会生成1000个文件,找出1000个文件出现最高频的词,然后再根据堆排序,选出100个频数最高的词。

Redis数据结构

string 字符串
hashmap 哈希表
linkedlist 双向链表
set 集合
zset 跳表
bitmap 位图
geo 地址位置
hyperloglog 基数统计算法

hashmap1.7与1.8

1)头插法变成了尾插法
2)先扩容在插入变成了先插入在扩容
3)数据结构类型变成了数组+链表+红黑树
4)计算位置的异或算法变成了一次
5)扩容的时候,根据h&length-1将哈希冲突的元素分到位置不同和位置+length的位置

模糊查询是否走索引

前通配 走全表
后通配 走索引
如果出现了查询电话码
where tel like “%1234”
可以改成 where tel_reverse like “4321%”

dns协议使用tcp还是udp

dns占用的端口是53,同时使用tcp和udp

dns使用tcp

辅域名的时候会定时(一般三个小时)向主域名服务器进行查询以便了解数据是否有变动,进行一次区域传输,使用tcp而不是udp,保证数据可靠。

dns使用udp

域名解析的时候使用udp即可,返回内容不超过512字节,用udp传输即可。不用经过三次握手,这样dns服务器负载更低,响应更快。

@AutoWired和@Resource

autowired注解是按照类型装配依赖对象,默认情况下,要求对象必须存在,如果允许存在null值,可以将它的属性required位false

resource注解和autowired一样,也可以将标注在字段或者属性的setter和getter方法上,但是它默认按照名称装配。名称通过@Resource的name属性设置。

resource是jdk的,autowired是spring的
resource按名称和类型都可,autowired只支持类型。

异常与错误

在java中,异常和错误都属于同一个类,Throwable。错误和异常都是Java异常处理重要的类,且各自包含大量子类。

exception是应用程序中出现的可预测,可恢复的问题,分为RuntimeException和编译期异常。

error大多数表示运行应用程序时比较严重的错误,大多数与程序员没有关系,可能是jvm出现了问题,比如jvm不再继续执行操作所需的内存资源时,将出现oom error

线程池的参数

 public ThreadPoolExecutor(int corePoolSize, // 1
                              int maximumPoolSize,  // 2
                              long keepAliveTime,  // 3
                              TimeUnit unit,  // 4
                              BlockingQueue<Runnable> workQueue, // 5
                              ThreadFactory threadFactory,  // 6
                              RejectedExecutionHandler handler ) { //7
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

核心线程数,最大线程数,线程结束持续最长时间,持续时间单位,拒绝策略,工作队列,线程创建工厂。

内部工作流程

如果核心线程没满,开启核心线程。如果核心线程数满了,看是否线程等待队列是否满了,没满排队。如果满了,看是否超过最大线程数,如果没出过,开启线程执行,如果超过,进行拒绝策略。

Innodb的表锁

1)sql语句用不到索引是不会使用行级锁,会使用表级锁把整张表锁住。
2)表字段变更
3)进行整表查询
4)like语句没走索引

SpringBoot重要注解

@Configuration 等同于xml的配置文件
@ComponentScan 组件扫描
@Autowired 自动注入 @Resource
@Controller @RestController
@SpringBootApplication
@EnableAutoConfiguration

Spring中Bean的生命周期

在这里插入图片描述

创建对象的方式

new关键字
反射机制 class类的newInstance方法/constructor类的newInstance方法
clone
序列化

Tcp的三次握手与四次挥手

在这里插入图片描述

三次握手

服务器是listen的状态,客户端发送SYN=1,seq=x(随机的),此时客户端的状态为SYN_SENT,服务器接收到了。返回SYN=1,ACK=1,ack=x+1,seq=y,接收到的时候,服务器端的状态变成SYN_RCVD 。此时客户端接收到,变成established,ACK=1,ack=y+1,seq =x+1,发送到服务器,服务器接收到之后也变成established。

四次挥手

客户端主动发出请求 FIN=1,seq =u变成FIN_WAIT状态,服务器接收到变成closed_wait状态,第一次还是可以发送数据,ACK=1,seq =v,ack=u+1,第二次直接发送,FIN=1,ACK=1,seq=w,ack=u+1, 客户端接收到了之后,进入到time_wait状态,等待2MSL,最后进入closed。

为什么客户端最后要等待2msl

保证客户端最后一个ack报文能发送到服务器,因为这个ACK报文可能丢失。如果服务端没收到最后一个报文,那么超时之后,他就会进行重传。

防止与三次握手类似的,在本连接已经失效的连接,在下一次新连接中收到。

Redis解决了什么问题

首先redis是一个nosql类型的数据库,他主要解决两个事情,降低磁盘io,将数据放在内存中,去除数据间的关系,只存数据。

Redis的key通用操作

expire key time
pexpire key milliseconds

加锁

ttl key

获取锁的时间

persist key

将锁变成持久化的锁

Redis的持久化

Redis分为两种RDB快照和AOF追加写两种方式,其实都是采用内部指令bgsave的方式,fork一个子进程来进行持久化。当然最原始有一个save指令,这个时候redis会被阻塞,进行持久化工作之后,才能继续进行工作。

RDB的优势劣势

rdb是一个紧凑的二进制文件,存储效率比较高。
在启动的时候容易恢复,效率高

但是,rdb不同的版本不兼容。
无法做到实时持久化,可能会丢数据,因为他的时间/改变次数在进行持久化。

AOF

aof的策略

每次操作都写磁盘
每秒
操作系统自定义

aof文件过大

会进行重写aof文件
aof文件体积超过64MB,或者比上次重写后的体积超过了100%。

Redis的事务

开启事务

mutli

执行事务

exec

取消事务

discard

事务的注意事项

如果有一个命令的书写格式有错误,那么全部事务都会被取消

如果命令有执行错误的,正常的命令会执行,错误的不会被执行。

分布式锁

setnx key value
在给这个分布式锁设置上时间,expire key time

Redis常见问题

缓存雪崩

大量的key在同一时间集中过期

解决方案

页面静态化架构
构建多级缓存
检测数据库,超时查询
灾难预警
限流降级

LRU和LFU切换
数据有效期进行调整,根据业务分类错峰,过期时间采用集中+随机
超热数据使用永久key
定期维护 对过期的热数据进行访问分析

缓存击穿

某个key过期,该key访问量巨大

解决方案

延长key的过期时间,实在不行设置为永久性key
缓存

缓存穿透

被攻击了,非正常的url访问
redis大面积没有命中

解决方案

白名单策略,使用bitmap
使用布隆过滤器

实施监控,进入黑名单

Redis数据类型

String 业务场景投票

key value 相当于java的中string

set key value
get key
del key
append key value

拓展操作

incr key
incr key increment

Hash类型 业务场景购物车

哈希表 hashmap

所有hash的操作,在set操作的前面加一个h

hset
hget
hdel

每个哈希可以存储2的32次幂-1的键值对

list类型 朋友圈点赞

linkedlist 双向链表

lpush/rpush 左右加
lpop/rpop 左右出

指定移除
lrem key count value

set类型 用于算法判断朋友 兴趣爱好

hashset 与hash相同,
左边只存储set,右边不存储

sadd key member1 member2
srem key member
判断集合数据总量
scard key
判断集合是否包含指定元素
sisimember key member

sorted-set 票选十大杰出青年

list+hash 有序的set

所有的都变成z开头

Redis高级数据类型

bigmaps位图

setbit key offset value
getbit key offset

统计电影一天被多少人看过

HyperLogLog

统计独立的uv
只记录数量,不保存数据,不是集合
核心是基数估算法

Geo

地理位置坐标点

Redis的主从复制

master复制写,slave负责读

主从复制的工作流程

建立连接阶段
数据同步阶段
命令传播阶段

建立连接阶段

master到slave的连接,保存slave的端口号
创建基于master的通道socket
slave周期发送ping命令

数据同步

全量复制

master执行bgsave,生成rdb文件, 建立缓冲区,发送给slave。
slave接受rdb,清空数据,执行rdb文件恢复过程

增量复制

master把每次aof,发送到复制缓冲区
slave接受命令,执行bgwriteaof,恢复数据

Redis的哨兵模式

哨兵是一个分布式系统,对主从结构每台服务器进行监控,当出现故障的通过投票机制选择新的master,并将所有的slave连接到新的master
哨兵也是一个redis服务器。

哨兵工作原理

同步各个节点的状态信息
通过ping获取各个哨兵的信息
获取master/slave的信息

选取slave成为master

找在线的,响应快的,与原来master断开最短的
将slave上升到master,将其他slave连接到新的master

常见线程池

FixThreadPool

用的linkedblockingqueue

SingleThreadPool

用的也是linkedblockingqueue

CachedThreadExector

用的是SynchronousQueue
非核心线程是Integer.MAX_VALUE

ScheduledThreadExector

定时器
DelayWorkQueue
keepAliveTime为0

线程池的工作队列

ArrayBlockingQueue
LinkedBlockingQueue
DelayQueue
PriorityBlockingQueue
SynchronousQueue

ArrayBlockingQueue
ArrayBlockingQueue(有界队列)是一个用数组实现的有界阻塞队列,按FIFO排序量。

LinkedBlockingQueue
LinkedBlockingQueue(可设置容量队列)基于链表结构的阻塞队列,按FIFO排序任务,容量可以选择进行设置,不设置的话,将是一个无边界的阻塞队列,最大长度为Integer.MAX_VALUE,吞吐量通常要高于ArrayBlockingQuene;newFixedThreadPool线程池使用了这个队列

DelayQueue
DelayQueue(延迟队列)是一个任务定时周期的延迟执行的队列。根据指定的执行时间从小到大排序,否则根据插入到队列的先后排序。newScheduledThreadPool线程池使用了这个队列。

PriorityBlockingQueue
PriorityBlockingQueue(优先级队列)是具有优先级的无界阻塞队列;

SynchronousQueue
SynchronousQueue(同步队列)一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQuene,newCachedThreadPool线程池使用了这个队列。

在项目中,maven依赖的两个jar包冲突了怎么办

通过exclusion标签解决

在这里插入图片描述

锁定版本

<dependencyManagement>
      <dependencies>
          <!--这里锁定版本为4.2.4 -->
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-beans</artifactId>
              <version>4.2.4.RELEASE</version>
          </dependency>
        <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-context</artifactId>
              <version>4.2.4.RELEASE</version>
          </dependency>
      </dependencies>
  </dependencyManagement>

Sql语句的执行顺序

在这里插入图片描述
from表
join on
where
group by
with
having
order by
limit
select

作为GC Roots的对象包含以下四种

虚拟机栈(栈桢中的本地变量表)中引用的对象
方法区中静态属性引用的对象
方法区中常量引用的对象
本地方法栈中(native方法)引用的对象

方法区的gc

该类的实例已经全部被回收,也就是java堆中不存在任何该类的任何实例
加载该类的classloader已经被回收
该类对应的java.lang.Class对象没有任何对象被引用,无法在任何地方通过反射访问该类的方法

sychronized作用于三种不同的形式

修饰实例方法

作用于当前实例加锁,进入同步代码块之前首先要获取当前实例的锁

修饰静态方法

作用于当前类对象加锁,进入同步方法之前首先要获取当前类对象的锁,这种用类对象加锁的方式实际上为了解决多个实例对象加锁的情况下带来线程不安全的情况

修饰代码块

指定加锁对象,对给定对象加锁 ,进入同步代码块前要获得给定对象的锁。

Spring中动态代理的两种方式

spring再执行aop的时候,执行了AnnotationAwareAspectJAutoProxyCreator类中某个方法。

1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

如何正确的停止一个线程

停止一个线程意味着在任务处理完任务之前停掉正在做的操作,也就是放弃当前的操作。停止一个线程可以用Thread.stop()方法,但最好不要用它。虽然它确实可以停止一个正在运行的线程,但是这个方法是不安全的,而且是已被废弃的方法。

在java中有三种方法可以终止正在运行的线程

使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。

使用stop方法强行终止,但是不推荐这个方法,因为stop和suspend及resume一样都是过期作废的方法。

使用interrupt方法中断线程。

停止不了的线程

interrupt()方法的使用效果并不像for+break语句那样,马上就停止循环,调用interrupt方法是在当前线程中打了一个停止标志

判断线程是否停止

Thread.java中提供了两种方法:
this.interrupted 测试当前线程是否已经中断
this.isInterrupted 测试当前线程是否已经中断
那么这两个方法有什么图区别呢?

我们先来看看this.interrupted()方法的解释:测试当前线程是否已经中断,当前线程是指运行this.interrupted()方法的线程。

OOM异常

在 Java 虚拟机规范中,对虚拟机栈这个区域规定了两种异常状况

1)如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError 异常;2)如果虚拟机栈可以动态扩展(当前大部分的 Java 虚拟机都可动态扩展,只不过 Java 虚拟机规范中也允许固定长度的虚拟机栈),当扩展时无法申请到足够的内存时会抛出 OutOfMemoryError 异常。
3)与虚拟机栈一样,本地方法栈区域也会抛出 StackOverflowError 和OutOfMemoryError 异常。

jdk8,Arrrays.sort用的什么排序

在这里插入图片描述

如果大于286

看是否具备结构。这里主要作用是看他数组具不具备结构:实际逻辑是分组排序,每降序为一个组,像1,9,8,7,6,8。9到6是降序,为一个组,然后把降序的一组排成升序:1,6,7,8,9,8。然后最后的8后面继续往后面找。。。

每遇到这样一个降序组,++count,当count大于MAX_RUN_COUNT(67),被判断为这个数组不具备结构(也就是这数据时而升时而降),然后送给之前的sort(里面的快速排序)的方法(The array is not highly structured,use Quicksort instead of merge sort.)。

如果count少于MAX_RUN_COUNT(67)的,说明这个数组还有点结构,就继续往下走下面的归并排序

如果大于并没有结构

直接走向快速排序

如果小于47直接插入排序

排序算法比较

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值