1.并发和并行

并发: 宏观上看是一个处理器"同时"处理多个任务(实际上多个任务轮流使用时间片)。微观上是同一时间只有一个任务在执行。(一个人同时吃两个苹果)
并行: 多个处理器同时处理多个任务。(两个人同时吃两个苹果)

2.实例变量和类变量。

类变量是被static所修饰的,没有被static修饰的叫实例变量也叫成员变量。同理也存在类对象和实例对象,类方法和实例方法。

<span style="color:#b4b4b4 !important"><span style="background-color:#1d1f21"><code class="language-java"><span style="color:#969896">//类变量</span>
<span style="color:#b294bb">public</span> <span style="color:#b294bb">static</span> String kunkun1 <span style="color:#a67f59">=</span> <span style="color:#b5bd68">"鸡你太美"</span><span style="color:#999999">;</span>

<span style="color:#969896">//实例变量(成员变量)</span>
<span style="color:#b294bb">public</span> String kunkun2 <span style="color:#a67f59">=</span> <span style="color:#b5bd68">"鸡你不美"</span><span style="color:#999999">;</span>
</code></span></span>
运行本项目java

3.说出下面程序的运行结果,及原因

<span style="color:#b4b4b4 !important"><span style="background-color:#1d1f21"><code class="language-java"><span style="color:#b294bb">public</span> <span style="color:#b294bb">class</span> InitialTest <span style="color:#999999">{</span>
    <span style="color:#b294bb">public</span> <span style="color:#b294bb">static</span> <span style="color:#b294bb">void</span> <span style="color:#81a2be">main</span><span style="color:#999999">(</span>String<span style="color:#999999">[</span><span style="color:#999999">]</span> args<span style="color:#999999">)</span> <span style="color:#999999">{</span>
        A ab <span style="color:#a67f59">=</span> <span style="color:#b294bb">new</span> B<span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
        ab <span style="color:#a67f59">=</span> <span style="color:#b294bb">new</span> B<span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
    <span style="color:#999999">}</span>
<span style="color:#999999">}</span>
<span style="color:#b294bb">class</span> A <span style="color:#999999">{</span>
    <span style="color:#b294bb">static</span> <span style="color:#999999">{</span> <span style="color:#969896">// 父类静态代码块</span>
        System<span style="color:#999999">.</span>out<span style="color:#999999">.</span><span style="color:#81a2be">print</span><span style="color:#999999">(</span><span style="color:#b5bd68">"A"</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
    <span style="color:#999999">}</span>
    <span style="color:#b294bb">public</span> A<span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#999999">{</span> <span style="color:#969896">// 父类构造器</span>
        System<span style="color:#999999">.</span>out<span style="color:#999999">.</span><span style="color:#81a2be">print</span><span style="color:#999999">(</span><span style="color:#b5bd68">"a"</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
    <span style="color:#999999">}</span>
<span style="color:#999999">}</span>
<span style="color:#b294bb">class</span> B <span style="color:#b294bb">extends</span> A <span style="color:#999999">{</span>
    <span style="color:#b294bb">static</span> <span style="color:#999999">{</span> <span style="color:#969896">// 子类静态代码块</span>
        System<span style="color:#999999">.</span>out<span style="color:#999999">.</span><span style="color:#81a2be">print</span><span style="color:#999999">(</span><span style="color:#b5bd68">"B"</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
    <span style="color:#999999">}</span>
    <span style="color:#b294bb">public</span> B<span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#999999">{</span> <span style="color:#969896">// 子类构造器</span>
        System<span style="color:#999999">.</span>out<span style="color:#999999">.</span><span style="color:#81a2be">print</span><span style="color:#999999">(</span><span style="color:#b5bd68">"b"</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
    <span style="color:#999999">}</span>
<span style="color:#999999">}</span>

结果:ABabab
</code></span></span>
运行本项目java
运行

    原因:
    ①执行顺序是 父类静态代码块(父类静态变量) -> 子类静态代码块(子类静态变量) -> 父类非静态代码块 -> 父类构造方法 -> 子类非静态代码块 -> 子类构造方法
    ②静态代码块(静态变量)只执行一次。

    4.抽象类和接口的区别

    抽象类只能单继承,接口可以实现多个。
    抽象类有构造方法,接口没有构造方法。
    抽象类可以有实例变量,接口中没有实例变量,有常量。
    抽象类可以包含非抽象方法,接口在java7之前所有方法都是抽象的,java8之后可以包含非抽象方法。
    抽象类中方法可以是任意修饰符,接口中java8之前都是public,java9支持private。
    扩展:普通类是亲爹,手把手教你怎么学,抽象类(多个类具有相同的东西,拿出来放抽象类)是师傅,教你一部分秘籍,然后告诉你怎么学。接口(规范了某些行为)是干爹,只给你秘籍,怎么学全靠你。

    5.Error和Exception有什么区别

    Error: 程序无法处理,比较严重的问题,程序会立即崩溃,jvm停止运行。
    Exception: 程序本身可以处理(向上抛出或者捕获)。编译时异常和运行时异常

    篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafc

    需要全套面试笔记及答案【点击此处即可/免费获取】https://docs.qq.com/doc/DQXdYWE9LZ2ZHZ1ho

    6.NoClassDefFoundError和ClassNotFoundException区别

    NoClassDefFoundError: 在打包时漏掉了某些类或者打包时存在,然后你把target里的类删除,然后jvm运行时找不到报错。
    ClassNotFoundException: 在编译的时候某些类找不到,然后报错。

    7.如果try{} 里有一个 return 语句,那么finally{} 里的代码会不会被执行,什么时候被执行,在 return 前还是后?

    会执行,在return之前执行,如果finally有return那么try的return就会失效。

    8.看一面代码执行结果是啥

    <span style="color:#b4b4b4 !important"><span style="background-color:#1d1f21"><code class="language-java"><span style="color:#b294bb">public</span> <span style="color:#b294bb">class</span> TryDemo <span style="color:#999999">{</span>
        <span style="color:#b294bb">public</span> <span style="color:#b294bb">static</span> <span style="color:#b294bb">void</span> <span style="color:#81a2be">main</span><span style="color:#999999">(</span>String<span style="color:#999999">[</span><span style="color:#999999">]</span> args<span style="color:#999999">)</span> <span style="color:#999999">{</span>
            System<span style="color:#999999">.</span>out<span style="color:#999999">.</span><span style="color:#81a2be">println</span><span style="color:#999999">(</span><span style="color:#81a2be">test1</span><span style="color:#999999">(</span><span style="color:#999999">)</span><span style="color:#999999">)</span><span style="color:#999999">;</span>
        <span style="color:#999999">}</span>
        <span style="color:#b294bb">public</span> <span style="color:#b294bb">static</span> <span style="color:#b294bb">int</span> <span style="color:#81a2be">test1</span><span style="color:#999999">(</span><span style="color:#999999">)</span> <span style="color:#999999">{</span>
            <span style="color:#b294bb">int</span> i <span style="color:#a67f59">=</span> <span style="color:#b5bd68">0</span><span style="color:#999999">;</span>
            <span style="color:#b294bb">try</span> <span style="color:#999999">{</span>
                i <span style="color:#a67f59">=</span> <span style="color:#b5bd68">2</span><span style="color:#999999">;</span>
                <span style="color:#b294bb">return</span> i<span style="color:#999999">;</span>
            <span style="color:#999999">}</span> <span style="color:#b294bb">finally</span> <span style="color:#999999">{</span>
                i <span style="color:#a67f59">=</span> <span style="color:#b5bd68">3</span><span style="color:#999999">;</span>
            <span style="color:#999999">}</span>
        <span style="color:#999999">}</span>
    <span style="color:#999999">}</span>
    结果 <span style="color:#b5bd68">2</span>
    </code></span></span>
    运行本项目java
    运行

    因为在return前,jvm会把2暂存起来,所以当i改变了,回到try时,还是会返回暂存的值。

    9.final关键字有哪些用法?

    修饰类: 不能被继承。
    修饰方法: 不能被重写。
    修饰变量: 声明时给定初始值,只能读取不能修改。如果是对象引用不能改,但是对象的属性可以修改。

    10.jdk1.8的新特性

    ①lambda 表达式
    ②方法引用
    ③加入了base64的编码器和解码器
    ④函数式接口
    ⑤接口允许定义非抽象方法,使用default关键字即可
    ⑥时间日期类改进

    11.http中重定向和转发的区别

    重定向发送两次请求,转发发送一次请求
    重定向地址栏会变化,转发地址栏不会变化
    重定向是浏览器跳转,转发是服务器跳转
    重定向可以跳转任意网址,转发只能跳转当前项目
    重定向会有数据丢失,转发不会数据丢失

    12.get和post请求的区别 delete、put

    get相对不安全,数据放在url中(请求行),post放在body中(请求体),相对安全。
    get传送的数据量小,post传送的数据量大。
    get效率比post高,是form的默认提交方法。

    13.cookie和session的区别

    存储位置不同:cookie放在客户端电脑,session放在服务器端内存的一个对象
    存储容量不同:cookie <=4KB,一个站点最多保存20个cookie,session是没有上限的,但是性能考虑不要放太多,而且要设置session删除机制
    存储数据类型不同:cookie只能存储ASCll字符串,session可以存储任何类型的数据
    隐私策略不同:cookie放在本地,别人可以解析,进行cookie欺骗,session放在服务器,不存在敏感信息泄露
    有效期不同:可以设置cookie的过期时间,session依赖于jsessionID的cookie,默认时间为-1,只需要关闭窗口就会失效

    14.java中的数据结构

    数组、链表、哈希表、栈、堆、队列、树、图

    15.什么是跨域?跨域的三要素

    跨域指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器施加的安全限制
    协议、域名、端口
    注意:localhost和127.0.0.1虽然都指向本机,但也属于跨域

    16.tomcat三个默认端口及其作用

    8005:这个端口负责监听关闭tomcat的请求。
    8009:接受其他服务器的请求
    8080:用于监听浏览器发送的请求

    17.throw 和 throws 的区别?

    throw:抛出一个异常。
    throws:声明一个异常。

    18.说一下你熟悉的设计模式

    单例模式: 保证被创建一次,节省系统开销。
    工厂模式: 解耦代码。
    观察者模式: 定义了对象之间的一对多的依赖,这样一来,当一个对象改变时,它的所有的依赖者都会收到通知并自动更新。
    代理模式: 代理对象具备被代理对象的功能,并代替被代理对象完成相应操作,并能够在操作执行的前后,对操作进行增强处理。
    模板模式: 较少代码冗余。例如:redis模板。

    19.实例化对象有哪几种方式

    ① new
    ② clone()
    ③ 反射
    ④先序列化在反序列化

    20.java中什么样的类不能被实例化

    抽象类: abstract关键字修饰的类。

    21.序列化和反序列化

    序列化: 把对象转为字节序列的过程,在传递和保存对象时,保证了对象的完整性和可传递性,便于在网络传输和保存在本地文件中。
    反序列化: 把字节序列转为对象的过程,通过字节流的状态和信息描述,来重建对象。

    22.序列化的优点

    将对象转为字节流存储到硬盘上,当JVM噶了的话,字节流还会在硬盘上等待,等待下一次JVM的启动,把序列化的对象,通过反序列化为原来的对象,减少储存空间和方便网络传输(因为是二进制)。

    23.你知道什么是单点登录吗?

    单点登录(SSO:Single Sign On): 同一账号在多系统中,只登录一次,就可以访问其他系统。多个系统,统一登录。
    列如:在一个公司下,有多个系统,比如淘宝和天猫,你登录上淘宝,就不用再去登录天猫了。

    24.实现单点登录的方式

    ① Cookie: 用cookie为媒介,存放用户凭证。登录上父应用,返回一个加密的cookie,访问子应用的时候,会对cookie解密校验,通过就可以登录。不安全和不能跨域免登。
    ② 分布式session实现: 用户第一次登录,会把用户信息记录下来,写入session,再次登录查看session是否含有对应信息。session系统不共享,使用缓存等方式来解决。
    ③重定向: 父应用提供一个GET方式的登录接口A,用户通过子应用重定向连接的方式访问这个接口,如果用户还没有登录,则返回一个登录页面,用户输入账号密码进行登录,如果用户已经登录了,则生成加密的token,并且重定向到子应用提供的验证token的接口B,通过解密和校验之后,子应用登录当前用户,虽然解决了安全和跨域,但是没前两种简单。

    25.sso(单点登录)与OAuth2.0(授权)的区别?

    单点登录: 就是一个公司多个子系统登录问题。
    OAuth2.0: 是授权问题,比如微信授权问题。是一种具体的协议。

    26.如何防止表单提交

    ①js屏蔽提交按钮。
    ②给数据库添加唯一约束。
    ③利用Session防止表单重复提交。会有一个token标记,表单提交的时候拦截器会检查是否一致,不一致就不通过。
    ④使用AOP切入实现。自定义注解,然后新增切入点,然后每次都记录过期时间,然后做比较。

    27.泛型是什么?有什么好处?

    本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
    好处:
    ①类型安全
    ②消除强制类型转换
    ③提高性能
    ④提高代码的复用性

    28.值传递和引用传递

    值传递: 函数调用时会把实际参数,复制一份到函数中,函数中对参数进行操作,并不会影响参数实际的值。
    引用传递: 将实际参数的地址值传递到函数中,函数对参数进行操作,会影响到实际参数的值。
    注意: java中不存在引用传递(即使传的是对象,那也只是传递了对象的引用地址的副本,也属于值传递)。

    二.java集合

    1.List、Set、Map的区别

    List集合有序、可重复的单例集合。
    Set集合无序、不可重复的单例集合。
    Map集合无序、k不可重复,v可重复的双例集合。

    2.List、Set、Map常用集合有哪些?

    List
    vector: 底层是数组,方法加了synchronized来保证线程安全,所以效率较慢,使用ArrayList替代。
    ArrayList: 线程不安全,底层是数组,因为数组都是连续的地址,所以查询比较快。增删比较慢,增会生成一个新数组,把新增的元素和原有元素放到新数组中,删除会导致元素移动,所以增删速度较慢。
    LinkedList: 线程不安全,底层是链表,因为地址不是连续的,都是一个节点和一个节点相连,每次查询都得重头开始查询,所以查询慢,增删只是断裂某个节点对整体影响不大,所以增删速度较快。

    Set
    HashSet: 底层是哈希表(数组+链表或数组+红黑树),在链表长度大于8时转为红黑树,在红黑树节点小于6时转为链表。其实就是实现了HashMap,值存入key,value是一个final修饰的对象。
    TreeSet: 底层是红黑树结构,就是TreeMap实现,可以实现有序的集合。String和Integer可以根据值进行排序。如果是对象需要实现Comparator接口,重写compareTo()方法制定比较规则。
    LinkedHashSet: 实现了HashSet,多一条链表来记录位置,所以是有序的。

    Map<key,value>双例结构
    TreeMap: 底层是红黑树,key可以按顺序排列。
    HashMap: 底层是哈希表,可以很快的储存和检索,无序,大量迭代情况不佳。
    LinkedHashMap: 底层是哈希表+链表,有序,大量迭代情况佳。

    3.ArrayList的初始容量是多少?扩容机制是什么?扩容过程是怎样?

    初始容量: 默认10,也可以通过构造方法传入大小。

    扩容机制: 原数组长度 + 原数组长度/2(源码中是原数组右移一位,也就相当于除以2)
    注意:扩容后的ArrayList底层数组不是原来的数组。

    扩容过程: 因为ArrayList底层是数组,所以它的扩容机制和数组一样,首先新建一个新数组,长度是原数组的1.5倍,然后调用Arrays.copyof()复制原数组的值,然后赋值给新数组。

    4.什么是哈希表

    根据关键码值(Key value)而直接进行访问的数据结构,在一个表中,通过H(key)计算出key在表中的位置,H(key)就是哈希函数,表就是哈希表。

    5.什么是哈希冲突

    不同的key通过哈希函数计算出相同的储存地址,这就是哈希冲突。

    6.解决哈希冲突

    (1)开放地址法
    如果发生哈希冲突,就会以当前地址为基准,再去寻找计算另一个位置,直到不发生哈希冲突。
    寻找的方法有:① 线性探测 1,2,3,m
    ② 二次探测 1的平方,-1的平方,2的平方,-2的平方,k的平方,-k的平方,k<=m/2
    ③ 随机探测 生成一个随机数,然后从随机地址+随机数++。

    (2)链地址法
    冲突的哈希值,连到到同一个链表上。

    (3)再哈希法(再散列方法)
    多个哈希函数,发生冲突,就在用另一个算计,直到没有冲突。

     篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafc

    需要全套面试笔记及答案【点击此处即可/免费获取】https://docs.qq.com/doc/DQXdYWE9LZ2ZHZ1ho

    (4)建立公共溢出区
    哈希表分成基本表和溢出表,与基本表发生冲突的都填入溢出表。

    7.HashMap的hash()算法,为什么不是h=key.hashcode(),而是key.hashcode()^ (h>>>16)

    得到哈希值然后右移16位,然后进行异或运算,这样使哈希值的低16位也具有了一部分高16位的特性,增加更多的变化性,减少了哈希冲突。

    8.为什么HashMap的初始容量和扩容都是2的次幂

    因为计算元素存储的下标是(n-1)&哈希值,数组初始容量-1,得到的二进制都是1,这样可以减少哈希冲突,可以更好的均匀插入。

    9.HashMap如果指定了不是2的次幂的容量会发生什么?

    会获得一个大于指定的初始值的最接近2的次幂的值作为初始容量。

    10.HashMap为什么线程不安全

    jdk1.7中因为使用头插法,再扩容的时候,可能会造成闭环和数据丢失。
    jdk1.8中使用尾插法,不会出现闭环和数据丢失,但是在多线程下,会发生数据覆盖。(put操作中,在putVal函数里) 值的覆盖还有长度的覆盖。

    11.解决Hashmap的线程安全问题

    (1)使用Hashtable解决,在方法加同步关键字,所以效率低下,已经被弃用。
    (2)使用Collections.synchronizedMap(new HashMap<>()),不常用。
    (3)ConcurrentHashMap(常用)

    12.ConcurrentHashMap的原理

    jdk1.7: 采用分段锁,是由Segment(继承ReentrantLock:可重入锁,默认是16,并发度是16)和HashEntry内部类组成,每一个Segment(锁)对应1个HashEntry(key,value)数组,数组之间互不影响,实现了并发访问。
    jdk1.8: 抛弃分段锁,采用CAS(乐观锁)+synchronized实现更加细粒度的锁,Node数组+链表+红黑树结构。只要锁住链表的头节点(树的根节点),就不会影响其他数组的读写,提高了并发度。

    13.为什么用synchronized代替ReentrantLock

    ①节省内存开销。ReentrantLock基于AQS来获得同步支持,但不是每个节点都需要同步支持,只有链表头节点或树的根节点需要同步,所以使用ReentrantLock会带来很大的内存开销。
    ②获得jvm支持,可重入锁只是api级别,而synchronized是jvm直接支持的,能够在jvm运行时做出相应的优化。
    ③在jdk1.6之后,对synchronized做了大量的优化,而且有多种锁状态,会从 无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁一步步转换。

    AQS (Abstract Queued Synchronizer): 一个抽象的队列同步器,通过维护一个共享资源状态( Volatile Int State )和一个先进先出( FIFO )的线程等待队列来实现一个多线程访问共享资源的同步框架。

    14.HashMap为什么使用链表

    减少和解决哈希冲突,把冲突的值放在同一链表下。

    15.HashMap为什么使用红黑树

    当数据过多,链表遍历较慢,所以引入红黑树。

    16.HashMap为什么不一上来就使用红黑树

    维护成本较大,红黑树在插入新的数据后,可能会进行变色、左旋、右旋来保持平衡,所以当数据少时,就不需要红黑树。

    17.说说你对红黑树的理解

    ①根节点是黑色。
    ②节点是黑色或红色。
    ③叶子节点是黑色。
    ④红色节点的子节点都是黑色。
    ⑤从任意节点到其子节点的所有路径都包含相同数目的黑色节点。
    红黑树从根到叶子节点的最长路径不会超过最短路径的2倍。保证了红黑树的高效。

    18.为什么链表长度大于8,并且表的长度大于64的时候,链表会转换成红黑树?

    因为链表长度越长,哈希冲突概率就越小,当链表等于8时,哈希冲突就非常低了,是千万分之一,我们的map也不会存那么多数据,如果真要存那么多数据,那就转为红黑树,提高查询和插入的效率。

    19.为什么转成红黑树是8呢?而重新转为链表阈值是6呢?

    因为如果都是8的话,那么会频繁转换,会浪费资源。

    20.为什么负载因子是0.75?

    加载因子越大,填满的元素越多,空间利用率越高,但发生冲突的机会变大了;
    加载因子越小,填满的元素越少,冲突发生的机会减小,但空间浪费了更多了,而且还会提高扩容rehash操作的次数。
    “冲突的机会”与“空间利用率”之间,寻找一种平衡与折中。
    又因为根据泊松分布,当负载因子是0.75时,平均值时0.5,带入可得,当链表为8时,哈希冲突发生概率就很低了。

    21.什么时候会扩容?

    元素个数 > 数组长度 * 负载因子 例如 16 * 0.75 = 12,当元素超过12个时就会扩容。
    链表长度大于8并且表长小于64,也会扩容

    22.为什么不是满了扩容?

    因为元素越多,空间利用率是高了,但是发生哈希冲突的几率也增加了。

    23.扩容过程

    jdk1.7: 会生成一个新table,重新计算每个节点放进新table,因为是头插法,在线程不安全的时候,可能会出现闭环和数据丢失。
    jdk1.8: 会生成一个新table,新位置只需要看(e.hash & oldCap)结果是0还是1,0就放在旧下标,1就是旧下标+旧数组长度。避免了对每个节点进行hash计算,大大提高了效率。e.hash是数组的hash值,,oldCap是旧数组的长度。

    24.HashMap和Hashtable的区别

    ①HashMap,运行key和value为null,Hashtable不允许为null。
    ②HashMap线程不安全,Hashtable线程安全。

    25.集合为什么要用迭代器(Iterator)

    更加安全,因为它可以确保,在当前遍历的集合元素被更改的时候,就会抛出 ConcurrentModificationException 异常。
    如果不用迭代器,只能for循环,还必须知道集合的数据结构,复用性不强。

    三.多线程

    1.线程是什么?多线程是什么?

    线程: 是最小的调度单位,包含在进程中。
    多线程: 多个线程并发执行的技术。

    2.守护线程和用户线程

    守护线程: jvm给的线程。比如:GC守护线程。
    用户线程: 用户自己定义的线程。比如:main()线程。

    拓展:
    Thread.setDaemon(false)设置为用户线程
    Thread.setDaemon(true)设置为守护线程

    3.线程的各个状态

    新建(New): 新建一个线程。
    就绪(Runnable): 抢夺cpu的使用权。
    运行(Running): 开始执行任务。
    阻塞(Blocked): 让线程等待,等待结束进入就绪队列。
    死亡(Dead): 线程正常结束或异常结束。

    4.线程相关的基本方法有 wait,notify,notifyAll,sleep,join,yield 等

    wait(): 线程等待,会释放锁,用于同步代码块或同步方法中,进入等待状态
    sleep(): 线程睡眠,不会释放锁,进入超时等待状态
    yield(): 线程让步,会使线程让出cpu使用权,进入就绪状态
    join(): 指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程。
    notify(): 随机唤醒一个在等待中的线程,进入就绪状态。
    notifyAll(): 唤醒全部在等待中的线程,进入就绪状态。

    5.wait()和sleep()的区别?

    ① wait() 来自Object,sleep()来自Thread。
    ② wait()会释放锁,sleep()不会释放锁。
    ③ wait()只能用在同步方法或代码块中,sleep()可以用在任何地方。
    ④ wait()不需要捕获异常,sleep()需要捕获异常。

    6.为什么 wait()、notify()、notifyAll()方法定义在 Object 类里面,而不是 Thread 类?

    ① 锁可以是任何对象,如果在Thread类中,那只能是Thread类的对象才能调用上面的方法了。
    ② java中进入临界区(同步代码块或同步方法),线程只需要拿到锁就行,而并不关心锁被那个线程持有。
    ③ 上面方法是java两个线程之间的通信机制,如果不能通过类似synchronized这样的Java关键字来实现这种机制,那么Object类中就是定义它们最好的地方,以此来使任何Java对象都可以拥有实现线程通信机制的能力。

    7.start()和run()的区别

    start()方法: 是启动线程,调用了之后线程会进入就绪状态,一旦拿到cpu使用权就开始执行run()方法,不能重复调用start(),否则会报异常。
    run()方法: 就相当于一个普通的方法而已。直接调用run()方法就还只有一个主线程,还是会顺序执行,也可以重复调用run()方法。

    8.实现多线程的方式

    ①继承Thread类。
    ②实现Runnable接口
    ③实现Callable接口
    ④线程池

    9.Runnable和Callable的区别

    ①Runnable没有返回值,Callable有返回值。
    ②Runnable只能抛出异常,不能捕获,Callable 能抛出异常,也能捕获。

    10.线程池的好处

    ① 线程是稀缺资源,使用线程池可以减少线程的创建和销毁,每个线程都可重复使用。
    ② 可以根据系统的需求,调整线程池里面线程的个数,防止了因为消耗内存过多导致服务器崩溃。

    11.线程池的七大参数

    corePoolSize: 核心线程数,创建不能被回收,可以设置被回收。
    maximumPoolSize: 最大线程数。
    keepAliveTime: 空闲线程存活时间。
    unit: 单位。
    workQueue: 等待队列。
    threadFactory: 线程工程,用于创建线程。
    handler: 拒绝策略。

    12.线程池的执行过程

    ①接到任务,判断核心线程池是否满了,没满执行任务,满了放入等待队列。
    ②等待队列没满,存入队列,等待执行,满了去查看最大线程数。
    ③最大线程数没满,执行任务,满了执行拒绝策略。

    13.四大方法

    ①ExecutorService executor = Executors.newCachedThreadPool(): 创建一个缓存线程池,灵活回收线程,任务过多,会oom。
    ②ExecutorService executor = Executors.newFixedThreadPool(): 创建一个指定线程数量的线程池。提高了线程池的效率和线程的创建的开销,等待队列可能堆积大量请求,导致oom。
    ③ExecutorService executor = Executors.newSingleThreadPool(): 创建一个单线程,保证线程的有序,出现异常再次创建,速度没那么快。
    ④ExecutorService executor = Executors.newScheduleThreadPool(): 创建一个定长的线程池,支持定时及周期性任务执行。

    14.四大拒绝策略

    ①new ThreadPoolExecutor.AbortPolicy(): 添加线程池被拒绝,会抛出异常(默认策略)。
    ②new ThreadPoolExecutor.CallerRunsPolicy(): 添加线程池被拒绝,不会放弃任务,也不会抛出异常,会让调用者线程去执行这个任务(就是不会使用线程池里的线程去执行任务,会让调用线程池的线程去执行)。
    ③new ThreadPoolExecutor.DiscardPolicy(): 添加线程池被拒绝,丢掉任务,不抛异常。
    ④new ThreadPoolExecutor.DiscardOldestPolicy(): 添加线程池被拒绝,会把线程池队列中等待最久的任务放弃,把拒绝任务放进去。

    15.shutdown 和 shutdownNow 的区别?

    ① shutdown没有返回值,shutdownNow会返回没有执行完任务的集合。
    ②shutdown不会抛出异常,shutdownNow会抛出异常。
    ③shutdown会等待执行完线程池的任务在关闭,shutdownNow会给所以线程发送中断信号,然后中断任务,关闭线程池。

    16.什么是死锁?

    各进程互相等待对方手里的资源,导致各进程都阻塞,无法向前推进的现象。

    17.造成死锁的四个必要条件

    互斥: 当资源被一个线程占用时,别的线程不能使用。
    不可抢占: 进程阻塞时,对占用的资源不释放。
    不剥夺: 进程获得资源未使用完,不能被强行剥夺。
    循环等待: 若干进程之间形成头尾相连的循环等待资源关系。

    18.线程安全主要是三方面

    原子性: 一个或多个操作,要么全部执行,要么全部不执行(执行的过程中是不会被任何因素打断的)。
    可见性: 一个线程对主内存的修改可以及时的被其他线程观察到。
    有序性: 程序执行的顺序按照代码的先后顺序执行。

    保证原子性
    使用锁 synchronized和 lock。
    使用CAS (compareAndSet:比较并交换),CAS是cpu的并发原语)。

    保证可见性
    使用锁 synchronized和 lock。
    使用volatile关键字 。

    保证有序性
    使用 volatile 关键字
    使用 synchronized 关键字。

    19.volatile和synchronized的区别

    ① volatile仅能使用在变量级别的,synchronized可以使用在变量、方法、类级别的
    ② volatile不具备原子性,具备可见性,synchronized有原子性和可见性。
    ③ volatile不会造成线程阻塞,synchronized会造成线程阻塞。
    ④ volatile关键字是线程同步的轻量级实现,所以volatile性能肯定比synchronized要好。

    Logo

    有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

    更多推荐