0
点赞
收藏
分享

微信扫一扫

软件工程复习笔记

天使魔鬼 2024-02-28 阅读 8

Java面试笔记

Java面试笔记-网络模块

TCP的三次握手

在这里插入图片描述
在这里插入图片描述

TCP报文头解读:
源端口(2字节)和目的端口(2字节):

序列号Sequence Number (Seq)(4字节):

Acknowledgment Number ACK确认码 (4字节):

Offset 偏移量 (4bits,即半个字节):

Reserved 保留域 (4bits):

TCP Flags TCP控制位 (1字节):

Window 滑动窗口 (2字节):

Checksum 奇偶校验 (2字节):

Urgent Pointer 紧急指针 (2字节):

TCP Options TCP可选项:

在这里插入图片描述

TCP的三次握手流程详解:

在这里插入图片描述

TCP三次握手的相关问题:

TCP的四次挥手

在这里插入图片描述

TCP四次挥手相关的问题:

全双工:双向同步通信。

一次tcp连接。从左到右分别为:第几次抓报的序号,抓包的时间,源IP地址,目的IP地址,协议,长度,信息。
其中信息的第一个53627 -> 80 为两边的端口号。
在这里插入图片描述

注:ACK确认报文不消耗Seq序列号,第四次和第六次包含了HTTP协议的TCP通信仍然序列号为1。

UDP和TCP的区别

UDP的报文结构:
在这里插入图片描述
Source Port: 源端口
Destination Port: 目标端口
Length: 数据包长度
Checksum: 奇偶校验值
data: 用户数据。

UDP的特点:

结论: UDP和TCP的区别

TCP的滑动窗口详解

TCP使用滑动窗口做流量控制与乱序重排
保证TCP的可靠性
保证TCP的流控特性

TCP的window字段:
用以告诉发送端接收端缓存的大小,以此控制发送端发送数据的速率。

TCP滑动窗口的计算过程:
在这里插入图片描述

滑动窗口的滑动原理:
发送方:

在这里插入图片描述
滑动窗口由category2和category3组成。

接收方:
在这里插入图片描述
滑动窗口由3组成。

HTTP简介

超文本传输协议HTTP主要特点:
支持客户/服务器模式:客户端通过url想服务端发送请求信息,服务端发送相应信息给客户端。
简单快速: 发送请求方法的时候只需发送请求的方法和路径, 请求的方法有get/post。程序规模小,传输速度快。
灵活:传输的数据类型多,使用content-type进行标记。
无连接: 每次连接只处理一个请求,服务器处理完客户的请求并收到客户的应答之后就断开连接,节省传输时间。http 1.1 版本之后默认使用长连接,在客户端应答之后等待一段时间才断开连接。
关于http的长连接理解:HTTP的长连接详解
无状态:协议对于事务处理没有记忆能力,如果处理的事务需要前面的信息则必须要重传。

HTTP请求结构:
在这里插入图片描述
在这里插入图片描述

HTTP 响应结构:
在这里插入图片描述
在这里插入图片描述

HTTP 请求/响应的步骤:

在浏览器窗口输入URL之后,按下回车后的经历:

HTTP 状态码:

GET请求和POST请求的区别
Cookie和Session的区别

Cookie的设置以及发送过程:
在这里插入图片描述

在这里插入图片描述

HTTP和HTTPS的区别

在这里插入图片描述

SSL(Security Sockets Layer,安全套接层)简介:

HTTPS数据传输流程:
在TCP连接建立之后:

注:所以原来所需要的3次连接之后发送消息,变成了3次连接+4次加密之后发送消息。

详细版本:

HTTP和HTTPS的区别:

Socket简介

Socket是对TCP/IP协议的抽象,是操作系统对外开放的接口
在这里插入图片描述
Scoket通信流程:
在这里插入图片描述

Java面试笔记-数据库模块

如何设计一个关系型数据库:
在这里插入图片描述
存储:就像os文件系统,将数据最终持久化存入磁盘中
存储管理:把逻辑存储最终映射到物理存储中,并且实现性能高效,及尽量少的做io,以为一次读一行的io和一次读多行的io消耗的性能基本差不多,所以每次读取尽量读多行或者块。
缓存机制:多读出来的数据放入缓存中,方便下次快速查找。

索引简介

时间复杂度快速分析

数据结构基础

相关考点:

Java集合框架简介

在这里插入图片描述
集合的源码大都集中在java.util这个包下面。
在这里插入图片描述
注:HashSet是由HashMap实现的。
TreeSet底层是由NavigableMap实现的,NavigableMap是由TreeMap实现的.

Map详解:
Map的key是通过Set实现的,在Map中的keySet()方法返回一个Set集合,所以可以去重.
Map的value是通过Collection实现的,所以允许重复。
在这里插入图片描述
HashMap(Java8 以前):数组+链表,数组查询快,删改慢;链表删改快,查询慢.,并且HashMap是线程不安全的,所以效率比较高。
缺点:如果连续发生哈希碰撞,则会使一个链表不停的增长,从而使性能从O(1)变为O(n)。
HashMap(Java8 及以后):数组+链表+红黑树。
在这里插入图片描述
连续发生哈希碰撞的情况性能优化为:性能从O(n)提高到O(logn)。

HashMap:从获取hash到散列的过程
在这里插入图片描述

HashMap、HashTable、 ConccurentHashMap的区别:
HashMap是采用的lazy load在首次使用的时候才会初始化:

HashMap:put方法的逻辑:

TREEIFY_THRESHOLD=8,MIN TREEIFY CAPACITY=64
超过8开始调用resize扩容,超过64进行树化。

HashMap:如何有效减少碰撞

HashMap扩容的问题:

HashTable 简介:

ConcurrentHashMap: 简介
CAS+synchronized使锁更细化
在这里插入图片描述
在ConcurrentHashMap中,synchronized只锁定当前链表或者红黑树的首节点,因此只要不发生哈希冲突就不会造成线程堵塞。
ConcurrentHashMap不允许键或值为空,HashMap可以。

ConcurrentHashMap:put方法的逻辑

ConcurrentHashMap总结:

HashMap、HashTable、 ConccurentHashMap的区别总结:

二叉树

一般考点为二叉搜索树,即左边的子节点要小于根节点,右边的子节点要大于根节点。
在这里插入图片描述
二叉树实现(python):
此为二叉搜索树

class Node:
    def __init__(self, key):
        self.left = None
        self.right = None
        self.val = key

def insert(root, key):
    if root is None:
        return Node(key)
    else:
        if root.val < key:
            root.right = insert(root.right, key)
        else:
            root.left = insert(root.left, key)
    return root

root = None
keys = [50, 30, 20, 40, 70, 60, 80]

for key in keys:
    root = insert(root, key)

二叉平衡树(AVL):
一个空树或者一个树的两个子节点的高度差不超过1.
不满足二叉平衡树的时候会进行左旋或者右旋。
左旋
本质就是,创建一个新的节点作为根节点的左子树,然后抛弃掉原本的右子树,让原本右子树的右子树成为新的右子树。
图解左旋:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
右旋思路同理。

B 树

在这里插入图片描述
B树的特征:

B+树:
在这里插入图片描述
B+树的特征:

B+树为什么更适合做储存索引:

Hash索引:
特点:

在这里插入图片描述

缺点:

BitMap位图索引简介:
特点:

在这里插入图片描述
缺点:

数据库索引部分总结:主流的索引是B+树,哈希索引和位图索引较小众。

索引模块:
密集索引和稀疏索引的区别:

MySql的主要存储引擎:

MyISAM和InnoDB的区别:

索引模块考点:

如何优化慢查询Sql:
分三步,
进入到数据库可视化界面中:

1. 根据慢日志定位慢查询sql
## 查询和查询相关的变量
show variables like '%quer%';
## 在显示的变量中, slow_query_log代表是否开启慢日志,
## long_query_time代表设置执行时间超过多少秒的sql记录到慢日志中。
## slow_query_log_file表示慢日志文件的位置。

# 显示慢日志的数量
show status like  '%slow queries%';

# 打开慢日志并设置记录时间为1秒钟。
# 注:在Query界面中用命令设置的参数在数据库重启后就会恢复默认设置,想要永久改变参数就要在ini文件中配置参数。
set global slow_query_log = on
set global long_query_time = 1

# 执行查询语句
select count(id) from person_info_large;
select name from person_info_large order by name desc;

2.使用explain等工具分析sql

# 在sql语句前加上explain即可分析sql查询语句情况。
explain select name from person info large order by name desc;
# explain返回的参数,id表示sql执行的顺序,id越大的越先执行。
# type:表示mysql找到数据行需要的方式,其中index和all为全表扫描。
# system>const>eq_ref>ref>fulltext>ref_or_null>index merge>unique_subquery>index subquery>range>index>all
# extra:需要优化的参数见下图

在这里插入图片描述

3.修改sql或者尽量让sql走索引

# 修改sql,查找有没有合适的索引,让查询参数查询带索引的关键字。
#原sql使用name字段,不是索引关键字。
select name from person_info_large order by name desc;
#查找建表语句后发现account字段有索引,修改后的sql如下。
select account from person info_large order by account desc;

# 为查询的字段添加索引。
alter table person_info_large add index idx_name(name);

#通过强制使用某个索引,测试使用不同索引的查询时间
explain select info larae force index (primary);
最左匹配原则
索引是建立得越多越好吗
锁简介

MyISAM与InnoDB关于锁方面的区别是什么

MyISAM适合的场景:

InnoDB适合的场景:

数据库锁的分类:

#1.先读取test_innodb的数据,得到Version的值为versionValue
select version from test innodb where id =2;#0
#2每次更新test_innodb表中的money字段时候,为了防止发生冲突,先去检查version再做更新#更新成功的话version +1
update test innodb set money = 123, version = 0 + 1 where version = 0 and id = 2;
#3假设在执行更新语句前,先执行了下面的更新操作。
update test innodb set money = 345, version = 0 + 1 where version = 0 and id = 2;
#那么在执行第一个更新语句就会更新失败,即返回的更新行数为0. 这时候可以根据程序中返回的count值对前端传输错误信息,提示数据更新失败。
update test innodb set money = 123, version = 0 + 1 where version = 0 and id = 2;
#这种手动提交时对比版本号的锁就是实现乐观锁的一种。
数据库事物的四大特性

ACID

事务隔离级别以及各级别下的并发访问问题:

当前读和快照读:

RC、RR级别下的InnoDB的非阻塞读如何实现:

InnoDB可重复读隔离级别下如何避免幻读:

Redis相关知识

主流应用架构:
在这里插入图片描述

缓存中间件:Memcache和Redis的区别

为什么Redis能这么快:

多路I/O复用模型:

传统的阻塞I/O模型:
在这里插入图片描述
多路I/O复用模型:
在这里插入图片描述

Redis采用的I/O多路复用函数:epoll/kqueue/evport/select ?

Redis的数据类型:

底层数据类型基础(非重点):

面试考点:从海量Key里查询出某一固定前缀的Key

如何通过Redis实现分布式锁

分布式锁需要解决的问题:

实现锁的步骤:

RedisService redisService = SpringUtils.getBean(RedisService class);
String result = redisService.set(lockkey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
if ("OK".equals(result)) (
//执行独占资源逻辑
doOcuppiedWork()
}

如何使用redis实现异步队列:

Redis如何做持久化:

Pipeline的优点:
相当于用一个buffer先存储一些从客户端发送的请求,然后批量发送给服务端进行处理,然后在批量发回给客户端,以此减少服务端和客户端之间的通信次数,提升处理性能。

Redis的同步机制:

哨兵机制 Redis Sentinel:

Redis的集群原理:

Java 虚拟机 JVM

面试考题:
谈谈你对Java的理解

设计的知识点:
平台无关性
GC
语言特性
面向对象
类库异常处理

平台无关性
Compile Once, Run Anywhere如何实现:
在配置了环境变量后,在执行javac指令的时候系统会直接去指定的jdk/bin目录下找到javac程序并执行。
class文件保存的就是java文件编译后的字节码, 之后使用java指令就能执行class文件并打印输出。
javap: jdk自带的反汇编器,可以查看java编译器生成的字节码。
javap -c: 反汇编,把字节码文件转成能看懂的java文件。
在这里插入图片描述
为什么JVM不直接将源码解析成机器码去执行
准备工作:每次执行都需要各种检查
兼容性:也可以将别的语言解析成字节码

JVM如何加载.class文件:
JVM是内存中的虚拟机:
在这里插入图片描述

谈谈反射:

反射的例子:

public class Robot {
    private String name;

    public void sayHello(String helloSentence){
        System.out.println(helloSentence+name);
    }

    private String sayHello2(String tag){
        return "hello" + tag;
    }
}

public class Reflect {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//        获取类
        Class rc = Class.forName("com.example.reflactexample1.demos.web.Robot");
//        创建类的实例,并强转,因为Class.forName返回的是T泛型。
        Robot r = (Robot) rc.newInstance();
        System.out.println("Class Name is:" + rc.getName());
//        获取方法对象,getDeclaredMethod能够获取private、 public、 protected的方法,或者所实现的接口的方法,不能获取继承的方法。
        Method getHello2 = rc.getDeclaredMethod("sayHello2", String.class);
        //访问私有方法时,要设置accessible为true,默认为false,如果不设置就会报错。
        getHello2.setAccessible(true);
        //调用方法,需要传入类实例和类的方法参数,invoke默认返回Object。
        Object str = getHello2.invoke(r, "user001");
        System.out.println("私有方法getHello2的输出为:" + str);
        // getMethod方法只能获取到类的public方法或者继承的方法和所实现的接口的方法。
        Method getHello1 = rc.getMethod("sayHello", String.class);
        getHello1.invoke(r, "Hello aaa");
//        获取类的私有属性
        Field name = rc.getDeclaredField("name");
        //设置accessible为true,因为是私有属性
        name.setAccessible(true);
        name.set(r, "XiaoMing");
        getHello1.invoke(r, "Hello aaa");
    }



}

反射的目的:

反射的作用:

谈谈ClassLoader:类从编译到执行的过程

ClassLoader定义:

ClassLoader的种类:

ClassLoader源码解析:
通过classLoader类的源码可以看出,负责加载类的loadClass方法,通过传入类的名字,返回代表这个类的Class类实例。

//源码第521行。
// 具体loadClass的实现,在之后的段落中。
// 关于参数resolve,也就是loadClass的第二个参数。如果之前使用过这个类,则设置为true,否则设置为false。If the class was found using the above steps, and the resolve flag is true, this method will theninvoke the resolveclass(Class) method on the resulting class object.
/**
     * Loads the class with the specified <a href="#binary-name">binary name</a>.
     * This method searches for classes in the same manner as the {@link
     * #loadClass(String, boolean)} method.  It is invoked by the Java virtual
     * machine to resolve class references.  Invoking this method is equivalent
     * to invoking {@link #loadClass(String, boolean) loadClass(name,
     * false)}.
     *
     * @param  name
     *         The <a href="#binary-name">binary name</a> of the class
     *
     * @return  The resulting {@code Class} object
     *
     * @throws  ClassNotFoundException
     *          If the class was not found
     */
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        return loadClass(name, false);
    }
//Params:
//name – The binary name of the class 
//resolve – If true then resolve the class
//Returns:
//The resulting Class object

注意:ClassLoader不同版本的变化:

jdk 11版本源码(ClassLoader.java):

// the built-in class loaders
    private static final BootClassLoader BOOT_LOADER;
    private static final PlatformClassLoader PLATFORM_LOADER;
    private static final AppClassLoader APP_LOADER;

每次用到class时,classLoader都会去这些路径下面查看是否有对应的文件。如果有文件就加载进系统。

类加载器的双亲委派机制:
注:如果底层的classLoader已经加载过类,则直接返回之前加载的类,如果没有加载过这个类,则首先把这个加载向上抛出,一直抛到最顶层的BootStrap ClassLoader,所以对于没加载过的类,最顶层的classLoader会首先开始尝试加载,如果无法加载再向下交给下层的classLoader完成。
在这里插入图片描述

使用双亲委派机制去加载类的目的:

类的加载方式:

loadClass和forName的区别:
类的装载过程。
在这里插入图片描述

Java 内存模型:

内存简介:
在这里插入图片描述

地址空间的划分:

JVM内存模型 – JDK8版本:
在这里插入图片描述

程序计数器(Program Counter Register):

Java虚拟机栈(Stack):

在这里插入图片描述

局部变量表和操作数栈:

递归为什么会引发java.lang.StackOverflowError异常:

虚拟机栈过多会引发java.lang.OutOfMemoryError异常:

本地方法栈

元空间(MetaSpace)与永久代(PermGen)的区别

MetaSpace相比PermGen的优势:

Java堆(Heap):

JVM调优:
JVM 三大性能调优参数-Xms -Xmx-Xss的含义:

Java内存模型中堆和栈的区别一内存分配策略:

一些关于内存的补充:

不同JDK版本之间的intern()方法的区别-JDK6 VS JDK6+:

Java 垃圾回收机制

判断对象为垃圾的标准:

几种垃圾回收算法:

复制算法(Copying):

标记-整理算法(Compacting):

主流算法 - 分代收集算法(Generational Collector):

jdk6 , jdk7:
在这里插入图片描述
Jdk8及其以后的版本:

在这里插入图片描述
GC的分类:

年轻代:尽可能快速地收集掉那些生命周期短的对象

对象如何晋升到老年代:

常用的调优参数:

老年代:存放生命周期较长的对象:

老年代:

触发FuIl GC的条件:

Stop-the-World:

Safepoint:

JVM的运行模式:

常见的垃圾收集器:
在这里插入图片描述
年轻代常见的垃圾收集器:
Serial收集器(-XX:+UseSerialGc,复制算法):

ParNew收集器(-XX:+UseParNewGC,复制算法):

Parallel Scavenge收集器(-XX:+UseParallelGC,复制算法):

老年代常见的垃圾收集器:
Serial Old收集器(-XX:+UseSerialOldGC,标记-整理算法):

Parallel Old收集器(-XX:+UseParallelOldGC,标记-整理算法):

CMS收集器(-XX:+UseConcMarkSweepGC,标记-清除算法):

G1收集器(-XX:+UseG1GC, 复制+标记-整理算法):
Garbage First收集器的特点:

GC相关的面试题:
Object的finalize()方法的作用是否与C++的析构函数作用相同:

Java中的强引用,软引用,弱引用,虚引用有什么用:
强引用(Strong Reference ):

软引用(Soft Reference):

弱引用(Weak Reference):

虚引用(PhantomReference):

强引用 >软引用 >弱引用 >虚引用
在这里插入图片描述
类层次结构:
在这里插入图片描述
引用队列(ReferenceQueue):

// ReferenceQueue源码第51行,可以看出队列只保存了一个head变量,剩下的链表通过enqueue方法的next储存。
static private class Lock{};
private Lock lock = new Lock();
private volatile Reference<? extends T> head = null;
private long queueLength=0;
//注意enqueue方法是传入一个reference对象
boolean enqueue(Reference<?extends T>r)
synchronized(lock){
ReferenceQueue<?>queue =r.queue;
if((queue ==NULL) || (queue == ENQUEUED)){
return false;
}
assert queue == this;
r.queue = ENQUEUED;
r.next=(head== null)?r:head; //传入的Reference对象的next指向head,也就是当前引用队列保存的值。
head = r;
queueLength++;

// Reference类的源码。类中有next属性值。
private T referent; /* Treated specially by GC */
volatile ReferenceQueue<? super T>queue;
/* When active:NULL
* pending:this
* Enqueued:next reference in queue (or this if last)
* Inactive:this
*/ 
/rawtype5/
Reference next;
多线程和并发

进程和线程的由来:
在这里插入图片描述

Java进程和线程的关系:

注:一个程序是一个可执行的文件,而一个进程则是一个执行中程序的实例。
JVM虚拟机并非单线程,虽然只创建一个主线程用于执行任务,但是也会创建其他的线程如GC垃圾回收线程。

Thread中的start和run方法的区别:
在这里插入图片描述

private static void attack(){
System.out.println("Fight")System.out.println("current Thread is :"+ Thread.currentThread().getName());
}

public static void main(String[]args){
	Thread t=new Thread(){
	public void run(){
	attack();
	}
};
System.out.println("current main thread is :" + Thread.currentThread().getName());
//t.run();
t.start();

Thread和Runnable是什么关系:

// Thread类和Runnable接口的源码
public Thread(Runnable target) {
        this(null, target, "Thread-" + nextThreadNum(), 0);
    }

public interface Runnable {
	abstract void run();
	}

如何给run()方法传参:
实现的方式主要有三种:
构造函数传参
成员变量传参
回调函数传参

如何实现处理线程的返回值:
实现的方式主要有三种:

// 如果子线程还未处理完成,主线程直接继续执行,那么就无法得到子线程的返回值,所以可以使主线程循环等待,查询子线程执行完成,继续执行主线程的程序。
public class CycleWait implements Runnable{
	private String value;
	public void run(){
		try {
		Thread.currentThread().sleep(millis:5000);
		}catch(InterruptedException e){
		e.printStackTrace();
	}
	value ="we have data now";
}
// 使用主线程等待法之前的main函数,输出Null。
public static void main(String[] args){
	CycleWait cw = new CycleWait();
	Thread t = new Thread(cw);
	t.start();
	System.out.println("value : " + cw.value);
}

//使用主线程等待法之后的main函数,输出:we have data now
public static void main(String[] args){
	CycleWait cw = new CycleWait();
	Thread t = new Thread(cw);
	t.start();
	while(cw.value == null){
	Thread.currentThread().sleep( millis:100);
	}
	System.out.println("value : " + cw.value);
}

//使用t.join法之后的的main函数,输出:we have data now
public static void main(String[] args){
	CycleWait cw = new CycleWait();
	Thread t = new Thread(cw);
	t.start();
	t.join();
	System.out.println("value : " + cw.value);
}
	
//Callable接口源码代码。
public interface Callable<V>{

	V call()throws Exception;
}

// FutureTask.java的源码第124行。可以看出FutureTask类的构造方法能够接收Callable类。
public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }
// FutureTask.java的源码第160行,能够判断Callable实力里面的call方法是否执行完成。
public boolean isDone() {
        return state != NEW;
    }
// FutureTask.java的源码第254行,FutureTask<V> implements RunnableFuture<V> {}实现了RunnableFuture,
// RunnableFuture<V> extends Runnable, Future<V>{} RunnableFuture接口实现了Runnable接口,所以 
// FutureTask中重写了Runable的run方法。
// 而FutureTask中的run方法又执行了callable中的call方法。
// 所以,如果在创建FutureTask实例的时候传入callable实例,从而执行带参构造函数,就可以通过FutureTask中的run方法执行实现了callable接口的实例的call方法。
public void run() {
        if (state != NEW ||
            !RUNNER.compareAndSet(this, null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }

// FutureTask.java的源码第185行,如果子线程没完成进行等待,完成了就返回值。
public V get() throws InterruptedException, ExecutionException {
        int s = state;
        if (s <= COMPLETING)
            s = awaitDone(false, 0L);
        return report(s);
    }

// 带时间控制的获得返回值方法。
public V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException {
        if (unit == null)
            throw new NullPointerException();
        int s = state;
        if (s <= COMPLETING &&
            (s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
            throw new TimeoutException();
        return report(s);
    }

代码例子:callable和futureTask。

public class MyCallable implements Callable<String>{
	@Override
	public string call()throws Exception{
	String value="test";
	System.out.println("Ready to work");
	Thread.currentThread().sleep( millis:5000);
	System.out.println("task done");
	return value;
	}
}

public class FutureTaskDemo{
	public static void main(String[] args)throws ExecutionException, InterruptedException{
	FutureTask<String> task= new FutureTask<String>(new MyCallable());
	new Thread(task).start();
	if(!task.isDone()){
		System.out.println("task has not finished, please wait!");
	}
	System.out.println("task return:"+ task.get());
	}
}

线程池的例子。

public cassThreadPoolDemo{
	public static void main(String[]args){
		ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
		Future<String> future = newCachedThreadPool.submit(new MyCallable());
		if(!future.isDone()){
			System.out.println("task has not finished, please wait!");
		}
		try {
		System.out.println(future.get());
		} catch (InterruptedException e){
			e.printStackTrace();
	}catch(ExecutionExceptione){
		e.printStackTrace();
	} finally {
	newCachedThreadPool.shutdown();
}
}
}

线程的状态:
六个状态:

sleep和wait的区别:

notify和notifyAl的区别:

yield:

如何中断线程:

线程转换图:
在这里插入图片描述

synchronized

线程安全问题的主要诱因:

互斥锁的特性

synchronized 锁的不是代码,锁的都是对象。

根据获取的锁的分类:获取对象锁和获取类锁:

对象锁和类锁的总结:

实现synchronized的基础:
Java对象头
Monitor

对象在内存中的布局:
对象头
实例数据
对齐填充

对象头的结构:
在这里插入图片描述
MarkWord:
在这里插入图片描述
Monitor:每个Java对象天生自带了一把看不见的锁。本身也是一个对象。
对象头的重量级锁(也就是synchronized):记录的是指向Monitor的起始地址的指针。每个对象都有一个Monitor与之关联。

Monitor锁的竞争、获取与释放:
在这里插入图片描述
什么是重入:

为什么会对 synchronized 嗤之以鼻:

Java6以后,synchronized性能得到了很大的提升:

自旋锁与自适应自旋锁:

synchronized的四种状态:

synchronized和ReentrantLock的区别:
ReentrantLock(再入锁):
位于java.util.concurrent.locks包
和CountDownLatch、FutureTask、Semaphore-样基于AQS实现
能够实现比synchronized更细粒度的控制,如控制fairness
调用lock()之后,必须调用unlock()释放锁
性能未必比synchronized高,并且也是可重入的

ReentrantLock公平性的设置:

ReentrantLock将锁对象化:

是否能将wait\notify\notifyAl对象化:

总结:

什么是Java内存模型中的happens-before:
Java内存模型JMM:

JMM中的主内存和工作内存:

JMM如何解决可见性问题:
在这里插入图片描述
指令重排序需要满足的条件:

A操作的结果需要对B操作可见,则A与B存在happens-before关系:

private int value = 0;
//线程1执行写操作
public void write(int input ){
	value = input;
}
//线程2执行读操作
public int read(){
	return value;
	}

CAS( Compare and Swap ):

Java线程池:

为什么要使用线程池:

ThreadPoolExecutor:

handler:线程池的饱和策略:

新任务提交execute执行后的判断:

线程池的状态:

状态转换图:

工作线程的生命周期:

String ,StringBuffer ,StringBuilder的区别:

Java 异常机制知识:

Error和Exception的区别:
Java的异常体系:
在这里插入图片描述
从概念角度解析Java的异常处理机制:

常见Error以及Exception:

Java的异常处理机制:

Java异常的处理原则:

高效主流的异常处理框架:
在用户看来,应用系统发生的所有异常都是应用系统内部的异常:

Java异常处理消耗性能的地方:

BlockingQueue:提供可阻塞的入队和出队操作:
在这里插入图片描述

//尝试往队列尾部去添加元素,添加成功返回true,添加失败抛出异常信息。
boolean add(@NotNull E e);
//尝试往队尾添加元素,成功返回true,失败返回false。
boolean offer( @NotNull E e);
//尝试往队列尾部去添加元素,如果队列满了则阻塞当前线程一直到添加成功。
void put( @NotNull E e)throws InterruptedException;
//尝试往队列尾部添加元素,如果队列满了,则等待timeout时间,如果时间到了还没添加成功,则返回false。
boolean offer(E e,long timeout, @NotNull TimeUnit unit)
throws InterruptedException;
// 从队列头部取元素,如果队列为空,则一直尝试取元素直到成功为止。
@NotNull E take()throws InterruptedException;

//尝试从队列头部获取元素,如果队列为空则等待timeout时间,如果时间到了还没取到头部元素,则返回空。
@Nullable E poll(long timeout, @NotNull TimeUnit unit)
throws InterruptedException;
//获取当前队列可获取元素数量。
int remainingCapacity();
//从队列中删除指定的对象。
boolean remove(Object o);
//查看队列中是否包含指定的对象
boolean contains(Object o);
// 把对象转移到指定的集合中。
int drainTo( @NotNull Collection<? super E> c);

Java的IO机制:
BIO、NIO、AIO的区别:

IOC(Inversion of Control):控制反转

ApplicationContext的功能(继承多个接口):

Bean的生命周期:

Spring AOP知识:

ACID
隔离级别
事务传播
在这里插入图片描述

举报

相关推荐

0 条评论