面试题目

1.如何中断一个线程

* 使用标志为退出线程
  • 最常用的方法,就是定义一个Boolean型的标志位,在线程的run方法中根据这个标志位是true还是false来判断是否退出,这种情况一般是将任务放在run方法中的一个while循环中执行的。

    public class ThreadFlag extends Thread {  
          public volatile boolean exit = false;  
          public void run() {  
              while (!exit) {
                  //do something
              }
          }  
          public static void main(String[] args) throws Exception  {  
              ThreadFlag thread = new ThreadFlag();  
              thread.start();  
              sleep(5000); // 主线程延迟5秒  
              thread.exit = true;  // 终止线程thread    
              thread.join();  
              System.out.println("线程退出!");  
          }  
      }
    
  • 或者,run方法中如果你不是使用while循环处理,则可以隔一段代码调用一次标志位判断:

    public class ThreadFlag extends Thread {  
          public volatile boolean exit = false;  
          public void run() {  
              //do something
              if (!exit)return;
              //do something
              if (!exit)return;
              //do something
              if (!exit)return;
              //do something
              if (!exit)return;
          }  
    }
    
* 使用stop方法强制终止线程
  • 使用stop方法可以强行终止正在运行或挂起的线程。我们可以使用如下的代码来终止线程:Thread.stop(),虽然这样可以终止线程,但使用stop方法是很危险的,就像突然关闭计算机电源,而不是按正常程序关机一样,可能会产生不可预料的结果,因此,并不推荐使用stop方法来终止线程。
* 使用interrupt终止线程
  • 使用interrupt方法来终断线程可分为两种情况:
    (1)线程处于阻塞状态,如使用了sleep方法。在调用interrupted后,sleep方法会抛出异常,然后输出错误信息sleep interrupted.
    (2)使用while(!isInterrupted()){……}来判断线程是否被中断。
    在第一种情况下使用interrupt方法,sleep方法将抛出一个InterruptedException例外,而在第二种情况下线程将直接退出。

  • //第一种情况
    public class ThreadInterrupt extends Thread {  
        public void run()  {  
            try {  
                sleep(50000);  // 延迟50秒  
            }  
            catch (InterruptedException e) {  
                System.out.println(e.getMessage());  
            }  
        }  
        public static void main(String[] args) throws Exception  {  
            Thread thread = new ThreadInterrupt();  
            thread.start();  
            System.out.println("在50秒之内按任意键中断线程!");  
            System.in.read();  
            thread.interrupt();  
            thread.join();  
            System.out.println("线程已经退出!");  
        }  
    }
    
    //运行结果50秒之内按任意键中断线程!
    sleep interrupted
    线程已经退出!
    
  • //第二种情况
    public class ThreadInterrupt extends Thread {  
    
          public void run() {  
              while (!isInterrupted()) {
                  //do something
              }
          }  
    
          public static void main(String[] args) throws Exception  {  
              Thread thread = new ThreadInterrupt();  
              thread.start();  
              thread.interrupt();  
              thread.join();  
              System.out.println("线程已经退出!"); 
          }  
      }
    
  • 注意:在Thread类中有两个方法可以判断线程是否通过interrupt方法被终止。一个是静态的方法interrupted(),一个是非静态的方法isInterrupted(),这两个方法的区别是interrupted用来判断当前线程是否被中断,而isInterrupted可以用来判断其他线程是否被中断。因此,while (!isInterrupted())也可以换成while (!Thread.interrupted())。

2. synchronized的方法锁与同步代码块锁的区别

  • 同步代码块:只能写在方法内部,同步代码块指同一时刻只有一个线程进入同步代码块,但是多个线程可以进入方法,但是只有拿到锁标记的线程才能进入同步代码块,上锁的是可以是当前的实例化对象,或者是一个变量对象。

    image-20200901112130632

    image-20200901112225936

  • 同步方法:同一时刻只能有一个线程进入同步方法,synchronized锁住的是当前的实例化对象,同一实例化对象会阻塞,不同实例化对象不会阻塞,

    image-20200901112042736

  • 全局锁:所有调用该方法的线程都会实现同步

    • 同步代码块传入class对象

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1a3guaC0-1604460988514)(https://gitee.com/wangpeng-01/lao_wang/raw/master/images/class(%E5%85%A8%E5%B1%80%E9%94%81)].png)

    • 修饰静态方法(所有调用该方法的线程都会实现同步)

      image-20200901112359417

3. wait与sleep的区别

  • sleep():让线程回到就绪状态,休眠一定时间,不会放弃锁标记,sleep()不一定非要用在同步代码块中,但在调用sleep()方法时需要捕获异常
  • wait():让线程进入无限期的休眠状态,线程进入阻塞状态,放弃锁标记,只能等待被其他线程唤醒,wait()只能用在同步代码块中,不用捕获异常

4.Java中的注解

5. 进程与线程的区别

  • 进程:操作系统中并发执行的多个任务(只有正在运行的程序,才能称为进程),进程是一个在内存中运行的应用程序,每个进程有一个独立的内存空间,一个进程可以有多个线程,多个线程共享数据,资源分配的最小单位
  • 线程:进程中的多个逻辑,称为线程,也称为轻量级进程,线程是一个顺序执行的过程
  • 区别:进程是资源分配的最小单位,线程是程序执行的最小单位,进程有自己独立的地址空间,每启动一个进程,系统都会为其分配地址空间,线程没有地址空间,它使用相同的地址空间共享数据。

6.进程间通信方式

  • 共享存储器系统
    • 在共享存储器中,相互通信的进程共享某些数据结构或共享存储区,进程之间能够通过这些空间进行通信。
      • 基于共享数据结构的通信方式(仅适用于传递少量的数据,通信效率地下,属于低级通信)
      • 基于共享存储区的通信方式(可以传输大量数据,多个进程可以通过该对共享区的读和写交换信息,属于高级通信方式,需要进行通信的进程在通信前先向系统申请获得共享存储区中的一个分区,并将其附加到自己的地址空间中)
  • 管道(pipe)通信系统
    • 管道:用于连接一个读进程和一个写进程以实现他们之间通信的一个共享文件,又叫pipe文件。可以有效地传输大量的数据
    • 管道机制必须提供三方面的能力:
      • 互斥:一个进程读或写时,另一个进程等待
      • 同步:一个进程写完数据后就去睡眠等待,直到另一进程读完后也睡眠等待,写进程继续写,重复此操作
      • 确定对方是否存在
  • 消息传递系统
    • 以格式化的信息为单位,将通信的数据封装在消息中,并利用操作系统提供的一组通信命令,在进程间通信
    • 该方式隐藏了通信实现的细节,使通信过程对用户透明化,降低了通信程序设计的复杂性和错误率,成为当前应用最为广泛的一类进程间的通信的机制
    • 该方式属于高级通信方式
      • 直接通信方式:利用os所提供的发送原语,直接把消息发给目标进程
      • 间接通信方式:发送和接受都通过共享中间实体(邮箱)的方式进行消息的发送和接收
  • 客户机-服务器系统(主流的通信方式)
    • 实现方法:
      • 套接字:套接字包含了通信目的地址,通信使用的端口号,通信网络的传输层协议,进程所在的网络地址,针对客户机或服务器程序提供的不同系统调用;这些是进程通信和网络通信的基本构件
        • 基于文件型:通信进程都运行在同一台机器的环境中
        • 基于网络型:非对称方式通信,通信双方的进程运行在不同主机的环境下,被分配一对套接字,一个属于接收进程,一个属于发送进程
      • 远程过程调用
        • 远程过程(函数)调用是一个通信协议,用于网络连接的系统。
      • 远程方法调用

7.进程的特征

1.动态性
2.独立性
3.并发性
4.异步性

8.HTTP和HTTPS的区别

  • Http是超文本传输协议,是明文传输;Https是具有安全性的SSL加密传输协议

  • Http
  1. 概念:超文本传输协议是互联网上应用最广泛的一种网络协议,Http最初的目的是提供了一种发布和接收HTML页面的方法。它可以使浏览器更加高效,

  2. 原理:

  3. 客户端的浏览器首先要通过网络与服务器建立连接,该连接是通过TCP来完成的,一般TCP的端口号是80。客户端发送的请求格式为:(请求行)统一资源标识符(URL)、协议版本号,请求正文(Http)

  4. 服务器接收到请求后,给予相应的响应信息。格式为:请求行,信息协议版本号,一个成功或者错误的代码,MIME信息(服务器信息,实体信息和可能的内容)

    HTTP请求报文
    请求头(get,post)
    请求的URI
    协议版本号
    可选的请求首部字段
    内容实体
    
    HTTP响应报文
    协议版本号
    响应的状态码
    状态码的原因短语
    可选的响应首部字段
    内容实体
    
  • Https
  1. 概念:是以安全为目标的Http通道,是Http的安全版。Https的安全基础是SSL。SSL协议位于TCP/IP协议与各种应用层协议之间,为数据通讯提供安全支持。
  2. HTTPS采用公开密钥加密(SSL)和共享密钥加密,交换密钥时采用公开密钥加密,之后建立通信交换报文阶段则使用共享密钥加密方式
  3. SSL,不对称加密,公开密钥交换算法,服务器申请CA时,会将自己的公钥提供给CA
  4. TLS是SSL的升级版
  5. TLS/SSL在传输层对网络连接进行加密,建立在可靠连接TCP之上

9.DNS域名解析(大概有十个过程)

  1. 浏览器先检查自身缓存中有没有被解析过的这个域名对应的ip地址,如果有,解析结束。同时域名被缓存的时间也可以通过TTL属性来设置、
  2. 如果浏览器还没有命中,浏览器会检查操作系统缓存中有没有对应的已解析过的结果。而操作系统也有一个域名解析的过程。在windows中可通过c盘里hosts的文件来设置,如果在这里制定了一个域名对应的ip地址,那浏览器会首先使用这个ip地址
  3. 如果还是没有命中域名,才会真正的请求本地域名服务器(LDNS)来解析这个域名
  4. 如果LDNS任然没有命中,直接跳到Root Server域名服务器请求解析
  5. 根域名服务器返回给LDNS一个所查询的主域名服务器地址
  6. 此时LDNS再发送请求给上一步的gTLD
  7. 接收请求的gTLD查找并返回这个域名对应的Name Server的地址,这个Name Server就是网站注册的域名服务器
  8. NameServer根据映射关系找到目标IP返回给LDNS
  9. LDNS缓存这个域名和对应的IP
  10. LDNS把解析的结果返回给用户,用户根据TTL值缓存到本地系统缓存中,域名解析过程至此结束
  • 主机向本地域名服务器的查询一般都是采用递归查询
    • 如果主机所查询的本地域名服务器不知道被查询域名的ip,那么本地域名服务器会以DNS客户的身份,向其他根域名继续发出查询的请求报文(代替该主机继续查询)
  • 本地域名服务器向根域名服务器查询通常采用迭代查询
    • 当根域名服务器收到本地域名服务器发出的迭代查询请求报文时,要么给出所要查询的IP地址,要么告诉本地域名服务器:“你下一步应当向哪一个域名服务器进行查询”。然后让本地域名服务器进行后续的查询(而不是代替本地域名服务器进行后续的查询)。

10.TCP/IP四层模型,以及各层用到的协议,tcp/ip分别在哪一层

  1. 应用层
  • 通过应用进程间的交互来完成特定的网络应用(应用进程间通信和交互的规则)
    • DNS(域名解析)
    • HTTP协议
    • SMTP(支持邮件)
  1. 传输层
  • 两台主机进程之间的通信提供的通用的数据传输服务
    • TCP(传输控制协议):提供面向连接的,可靠的数据传输服务
    • UDP(用户数据报协议):提供面向无连接的,最大努力交付的数据传输服务
  1. 网络层
  • 把运输层产生的报文封装成分组或包进行传送
  1. 数据链路层
  • 将网络层较下来的IP数据包封装成帧

11.三次握手/四次挥手

  • 三次握手

第一次:客户端发送连接请求(SYN)并随机产生一个序列号seq

第二次:服务器接收到客户端发送的请求后,发送一个标志位的SYN=1,产生一个序列号ack=客户端发送的序列号加1,确认号ACK=1,随机产生一个seq

第三次:客户端收到服务器回复后,客户端回复ACK=1,ack=服务器随机产生和的序列号+1

建立连接

  • 四次挥手

第一次:客户端发送断开连接请求FIN,客户端进入结束等待状态

第二次:服务器收到客户端的断开连接请求FIN后,发送一个ACK给客户端,确认号为接收到的序号+1,服务器端进入close_wait状态

第三次:服务器发送一个FIN,用来关闭服务器到客户端的数据传送,server进入到LAST_WAIT状态

第四次:客户端收到FIN后,客户端进入TIME_WAIT状态,接着发送一个ACK给服务器,确认序号是收到的服务器的序号+1,服务器关闭,四次挥手完成

12.ssm

13.synchronied的底层实现原理

14.jvm内存模型

  1. 虚拟机栈
  • 线程私有,每个方法执行的时候会创建一个栈帧,存储了局部变量,对象的引用,常量池对象的引用,虚拟机栈是一个连续的内存空间,可以动态扩展,直到无法申请足够的内存
  1. 方法区
  • 线程共享,存储被虚拟机加载的类信息,常量,静态变量(此部分不可以被垃圾回收)
  • 运行时常量池:方法区的一部分,具有动态性,存放字面量以及符号引用
  • 线程共享,在虚拟机启动的时候被创建,存放对象实例
  • 堆可以扩展
  • 垃圾回收的主要区域
  • 字符串常量池在堆中
  1. 程序计数器
  • 线程私有,每条线程都有一个独立的程序计数器,记录当前指令的地址
  1. 本地方法栈
  • 线程私有,主要为虚拟机使用的Native方法服务

    JDK1.8之后,方法区放入了本地内存中,字符串常量池放入了堆中
    

15.HashMap为什么是线程不安全的

HashMap在JDK1.8之前采用的是头插法,在1.8之后采用的是尾插法;因为头插法会造成死链
1. 为什么线程不安全
->因为扩容机制,hashmap默认大小为16,当数据过大时,hashmap就需要扩容区支持存放更多的数据(扩容默认时2的幂次方)
15.1 ConcurrentHashMap
1.采用分段锁,将一个Map拆分成很多个小的HashTable(默认为16个),在get和put的时候根据key.hashcode()算出放到哪个空间中(Segment)。
在ConcurrentHashMap中,既不能不锁(HashMap),又不能全锁(HashTable),,所以就搞出来了个分段锁,只锁其中的一部分,用到哪部分就锁哪部分。类似于,在一个很大的仓库中有很多的隔间,每个隔间在同一时刻只能允许一个人进去存取东西。在存取之前会有一个索引,告诉你你要的资源在那个部分,当这个隔间空闲时,就可以进行操作,但是当隔间有人的时候,就要等着。
2.在JDK1.8之前采用的是分段锁。在1.8之后做了优化

16.volatile和synchronized的区别

  1. volatile
1.volitile关键字用来修饰变量,使得该变量在多个线程之间可见,多个线程对共享变量的操作实际上是各自线程的私有拷贝数据的操作,这可能会出现数据不一致的情况,基于这种情况可以用volatile进行修饰,可以保证多个线程数据的修改可以直接刷新到内存中,每一次读共享变量可以强制从主存中读,保证了共享变量的可见性
2.volatile还会保证有序性(通过禁止指令重排来保证)
  1. synchronized
  • 解决执行控制问题,他会阻止其他线程获取当前对象的锁,这样就使得当前对象中受到synchronized保护的代码无法被其他线程访问,也就无法并发执行.synchronized还会创建一个内存屏障,内存屏障保证了所有cpu操作都会直接刷到主存中,从而保证了操作的内存可见性,同时也使得先获得这个锁的线程的所有操作,都happens-before于随后获得这个锁的线程的操作。
  1. 区别
  • volatile本质是在告诉jvm当前变量在寄存器中的值是不确定的,需要从主存中读取;synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞
  • volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的
  • volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性
  • volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
  • volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化
java多线程之间是通过共享内存进行通信的,在通信过程中会存在一系列问题如可见性,原子性,顺序性问题,JVM就是围绕着多线程通信,以及一系列的特性而建立的模型,JMM定义了一些语法集,映射过来就是volatile和synchronized等关键字

17.临界资源

概念:一次只允许一个进程使用的共享资源;各进程采用互斥的方式,实现共享的资源叫做临界资源
18.1 临界区
  • 每个进程中访问临界资源的那段代码成为临界区,每次只允许一个进程进入临界区,进入后,不允许其他线程进入

18.GC

  1. 垃圾判定算法
  • 引用计数

    原理:在对象中添加一个引用计数器,每当有一个地方引用用它,就让计数器加一,引用失效时,值就减一,当计数器值为0时,对象就不可能在被调用
    优点:原理简单,效率也高
    缺点:必须要配合大量额外的处理才能保证正确的工作,也很难解决对象之间循环调用的问题
    
  • 可达性分析

    原理:如果某个对象到GCRoots之间没有任何引用链相连(GCRoots到这个对象不可达),证明此对象不能在调用
    可以被作为GCRoots的对象:
    	1.虚拟机栈中引用的对象(各个线程被调用的方法,堆栈中使用到的参数,局部变量,临时变量)
    	2.方法区中静态属性引用的对象
    	3.字符串常量池里的引用
    	4.本地方法栈中引用的对象
    	5.被synchronized同步锁持有的对象
    
  1. 垃圾回收方法
  • 标记-清除

    原理:标记出所有需要被回收的对象,在标记完成后统一回收掉所有被标记的对象那个,也可以反过来,标记不需要被回收的对象,标记完成后,回收掉没有被标记的对象
    优点:最基础的垃圾回收算法,其他的垃圾回收算法都是在其缺点基础上改进的
    缺点:
    	1.执行效率不太稳定,如果java堆中包含了大量对象,而且其中大部分是被回收的,这时需要大量的标记和清除的动作,导致标记和清除的效率随着对象的数量的增长而降低
    	2.空间碎片化的问题:标记清除之后,会产生大量的不连续的内存碎片,空间碎片过多可能会导致之后程序在运行过程中需要分配比较大对象时没有足够的连续内存而不得不提前触发另一次垃圾收集动作
    
  • 标记-复制

    原理:将内存按照容量分为大小相等的两块,每次只使用其中的一块,当这一块内存用完了,就将这一块内存中还存活的对象复制到另外一块内存,将已使用过的这一块内存全部回收
    优点:解决了标记-清除算法面对大量可回收对象时执行效率低的问题,运行高效,分配内存时不用考虑空间碎片的问题
    缺点:每次只能用一半的内存,空间浪费比较严重
    
  • 标记-整理

    原理:标记出所有需要被回收的对象,在标记完成后,将所有标记过的对象向空间的一端移动,然后直接清理掉边界以外的内存 
    优点:不会产生碎片化问题
    缺点:移动大量存活对象,将会是一种极为负重的操作
    

19.四种引用

  1. 强引用:
Object obj = new Object();
//只要强引用关系还在,GC就不会回收掉被引用的对象
  1. 软引用
还有用但非必须的对象,(SoftReference)只被软引用关联着的对象,在系统将要发生内存溢出前,才会把这些对象列进回收范围中进行二次回收,如果这次回收还没有足够的内存,系统才会抛出内存溢出异常
  1. 弱引用
也是描述非必须的对象,比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集为止,当垃圾收集器开始工作,无论内存够不够用,都会被回收
  1. 虚引用
最弱的一种引用关系,一个对象是否有虚引用的存在,完全不会对其生存时间造成影响,也无法通过虚引用来获取一个对象的实例,为一个对象设置虚引用的目的是为了在这个对象被垃圾回收器回收之前收到一个系统通知

20.类加载

过程:
	1.加载
	2.验证
	3.准备
	4.解析
	5.初始化
	把类的.class文件中类的信息读到内存中,产生与所加载类对应的class对象,加载完成之后,进入验证,准备为静态变量分配内存空间,并且设置默认的初始值
20-1.双亲委派模型
类加载器接收到类加载的请求之后,首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是这样,因此所有的类加载请求最终都会传送到启动类加载器中;只有当父类加载器反馈自己无法完成时,子类才会尝试自己去加载

好处:不管是哪个加载器加载这个类,最终都会到启动类加载器中加载,可以保证不同的类加载器对象最终得到的都是同意Object对象

21.Session和Cookie

  • HTTP是一种无状态的协议,为了分辨链接是谁发起的,需自己去解决这个问题。不然有些情况下即使是同一个网站每打开一个页面也都要登录一下。而Session和Cookie就是为解决这个问题而提出来的两个机制
21-1.Session
1.使用场景:session一个场景是购物车,添加了商品之后客户端处可以知道添加了哪些商品,而服务器端如何判别呢,所以也需要存储一些信息就用到了session。
2.概念:session是存在服务器的一种存放数据的类,是HashTable结构(session的默认存储时间是30分钟,超时自动销毁)
3.session保存在服务器理论上没有限制,只要内存够大
4.当用户第一次访问session时,服务器会创建一个session,并且创建一个cookie,cookie中的键为JSESSIONID,值为session的ID,将session放入HashTable中,HashTable中键为session的ID,值为session本身,并将cookie返回给浏览器,当用户第二次访问时,服务器会先检查浏览器中是否有键为JSESSIONID,如果有,获取cookie的值,此时cookie的值就是session的id,在存放session的HashTable中找到对应的值给用户使用;如果没找到,说明此用户是第一次访问,创建session。
21-2.Cookie
  • cookie生命周期,有两种,一种是默认的会话级cookie,随着浏览器关闭而消失,比如保存session的cookie
  • 还有一种是非会话级的cookie,比如七天免登陆的,这时间需要设置有效期setMaxAge
1.概念:通俗讲,是访问某些网站后,存本地存储的一些信息,下次访问时就减少一些步骤;Cookies是服务器在本地机器上存储的小段文本并随每一个请求发送至每一个服务器,是客户端保持状态的方案(服务器创建,浏览器保存)
2.使用场景:登录网站,今输入用户名密码登录了,第二天再打开很多情况下就直接打开了。这个时候用到的一个机制就是cookie。
3.cookie中的值时异key,value的方式存储;cookie的过期时间可以设置,如果不设置,浏览器关闭,cookie就消失了;
21-3.区别
1.session可以存储任意类型的java对象,cookie只能存储String类型的字符串
2.cookie在客户端可以伪造,不安全
3.session过多会消耗服务器资源
4.域的支持范围不一样,a.com的cookie在a.cookie下都能用,而www.a.com的session在api.a.com下就不能用

22.索引

1.概念:数据库索引是数据库管理系统中一个排序的数据结构,用来增加查询效率,mysql中的索引用的是B+树,索引实现通常用B树和B+数实现
2.创建索引的好处:
	1.通过创建索引可以在查询过程中,提高系统的性能
	2.通过创建的唯一索引,可以保证数据库表中每一行数据的唯一性
	3.在使用分组和排序子句进行数据检索时,可以减少查询中分组和排序的时间
3.创建索引的坏处
	1.创建和维护索引时需要耗费时间,并且随着数据的增多,时间也会越来越长
	2.索引需要占用物理空间
	3.在对表中的数据进行增加删除时需要耗费较多的时间,因为索引也需要动态的维护
4.索引创建的地方
	1.需要经常搜索的列上,作为主键的地方
	2.经常用在连接的列上,这些列主要是一些外键
	3.根据范围进行搜索的列上,经常需要排序的列上,以及经常使用where子句的列上
5.索引的分类和使用
	1.主键索引:非空且唯一
	2.普通索引:没什么限制
	3.唯一索引:索引列的值必修唯一
	4.复合索引:多个字段上建立的索引,提高复合条件查询效率
6.索引失效情况
	1.主键索引时条件中使用or
	2.like中以%开头
	3.列类型是字符串,不加引号,失效

23.CAS算法(比较交换算法)

CAS包含三个参数(内存中的值,预期值,新值) 

24.JMM

概念:Java内存模型,主要是为了规定线程和内存之间的一些关系。
设计:系统中存在一个主内存,Java中所有的变量都储存在主内存中,对于所有的线程都是共享的。每个线程都有自己的工作内存,工作内存中保存的是主存中某些变量的拷贝,线程对所有变量的操作都是在自己的工作内存中进行,线程之间无法直接访问,变量传递需要通过主存完成

25.线程池

线程池运行流程:
	线程池主要就是指定线程池核心线程数的大小,最大线程数,存储队列,拒绝策略,空闲线程的存活时长。
	当需要任务大于核心线程数的时候,就开始把任务往存储队列中加,当存储队列满的时候,就开始增加线程池创建的数量,如果当线程池数量达到最大时,就开始执行拒绝策略,比如说记录日志,直接丢弃或者丢弃最老的任务
	
四种线程池:7m
	newSingleThreadExecutor(单个线程的线程池)
	newFixedThreadExecutor(固定数量的线程池,需要自己传入参数)
	newCachedThreadExecutor(可缓存线程池数,系统自己根据需要来创建)
	newScheduleThreadExecutor(大小无限制的线程池,支持定时和周期的执行线程)

用的最多的是:
	newCachedThreadExecutor

26.java线程的几种状态

初始状态
就绪状态
运行状态
等待状态(有限期等待(sleep),无限期等待(join))
阻塞状态(wait())
终止状态

27.yield与notify(notifyAll)

yield:暂停当前正在执行的线程(放弃当前的cpu资源)回到就绪状态,以允许具有相同优先级的其他线程获得运行机会,但实际中,可能并不能达到预期的效果,可能该线程还会被选中执行

28.ArrayList与LinkedList

ArrayList:
	1.基于数组实现的
	2.插入删除慢,查询快
	3.Array是基于索引的数据结构,使用索引再数组中搜索和读取是很快的,可以直接返回数组中index位置的元素,因此再随机访问集合元	    素上有较好的性能,Array获取元素的时间复杂度是o(1),但是插入删除数据开销很大
LinkedList:
	1.基于双向链表实现的
	2.插入删除快,查询慢
	3.可以根据索引来随机访问集合中的元素,LinkedList实现了Deque接口,可以代表一个双向队列,栈以及List使用
	4.LinkedList随机访问的性能较差,他需要先获取索引的位置,但是插入删除很快
使用场景:
	1.如果程序对数据有较多的访问,ArrayList更好点
	2.如果程序对数据有较多的插入删除,用LinkedList
	3.当Arraylist再靠近末尾的地方插入删除时,可能要比LinkedList快一点

29.常用的模式

29-1.单例模式
单例模式的好处:
	1.某些类创建对象比较频繁,特别是一些大型的对象,这是一笔很大的开销
	2.降低了new的操作,降低了GC的压力
	3.比如一些核心的管理类,控制着整个项目的运行,如果该类创建了多个的话,系统就会乱掉
缺点:
	单例类职责过重,违背了单一职责原则
应用场景:
	打印机
	回收战
	任务管理器
//饿汉模式
class A{
    //私有的构造方法,不能new对象
    private A(){}
    //提前创建好对象,当调用时直接返回创建好的对象
    private static A instance = new A();
    public static A newInstance(){
        return intance;
    }
}
//懒汉模式
class A{
    private A(){}
    private static A instance = null;
    public static A newInstance(){
        if(instance == null){
            synchronized(A.class){
                instance = new A();
            }
        }
        return instance;
    }
}
//静态内部类的懒汉式
class A(){
    private A(){}
    private static class newInstance(){
        static A instance = new A();
    }
    public static A newA(){
        return newInstance.instance;
    }
}
29-2.工厂模式
1.建立一个工厂类,对实现了统一接口的一些类进行实例的创建
2.应用场景:
	出现了大量的需要创建实例对象时,并且实现了共同的接口,可以通过工厂模式进行创建
//代码实现
public interface Sender {
	public void Send();
}

public class MailSender implements Sender {
	@Override
	public void Send() {
		System.out.println("this is mailsender!");
	}
}
public class SmsSender implements Sender {
    @Override
    public void Send() {
        System.out.println("this is sms sender!");
    }
}

public class SendFactory {
	public static Sender produceMail(){
		return new MailSender();
	}
	public static Sender produceSms(){
		return new SmsSender();
	}
}
29-3.代理模式
1.为某对象提供一种代理以控制对该对象的访问
2.应用场景:
	1.如果已有的方法在使用的时间需要对原有的方法进行相应的修改时,可以采用代理模式,这样可以不在原有的方法上进行修改,不会违反对扩展开放,对修改关闭的原则
	2.对原有的方法的结果产生控制时
	3.使用代理模式可以将功能划分的更加清晰,有助于后期维护
//代码实现
public interface Sourceable {
	public void method();
}

public class Source implements Sourceable {
	@Override
	public void method() {
		System.out.println("the original method!");
	}
}

public class Proxy implements Sourceable {
	private Source source;
	public Proxy(){
		super();
		this.source = new Source();
	}
	@Override
	public void method() {
		before();
		source.method();
		atfer();
	}
	private void atfer() {
		System.out.println("after proxy!");
	}
	private void before() {
		System.out.println("before proxy!");
	}
}

30.标注

31.ICMP

32.新生代老年代的垃圾回收算法

1.新生代中的清除算法(标记复制算法)
	新生代中的内存空间默认分为Eden,To Survivor和From Survivor三个区域,默认大小为8:1:1,新对象创建后一般在Edeu中,个别特别大的对象会直接在老年代中创建,新生代发生一次GC后,会把Eden区和Survivor区中的对象复制到另外一个Survivor中,反复几次后,会将存活的对象放入老年代中
2.老年代中的清除算法(标记整理算法)
	可以避免复制带来的效率地的问题和清除带来的碎片化的问题

33.生产者消费者问题

34.ThreadLocal

作用:
	实现在线程的上下文传递对象,为每一个线程创建一个副本
在实际开发中的使用场景:
	mybatis管理sqlsession,管理connection
//ThreadLocal.get()源码
public T get() {
    	//获取当前线程
        Thread t = Thread.currentThread();
    	//获取当前线程的map
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            //以当前线程为key获取一个键值对
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                //获取当前线程键值对的value,就是我们存放到里面变量的副本
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

//ThreadLocal.set()源码
public void set(T value) {
    	//同样获取当前线程
        Thread t = Thread.currentThread();
    	//获取当前线程的map
        ThreadLocalMap map = getMap(t);
        if (map != null)
            //以当前线程为key放入到map集合中
            map.set(this, value);
        else
            createMap(t, value);
    }

35.获得类对象的3种方法

//1.通过类名.class获得
Class c = 类名.class;
//2.通过类的对象.getClass()获得
Student stu = new Student();
Class c = stu.getClass();
//通过Class.forName("类的全限定名")
Class c = Class.forName("类的全限定名");

36.数据库的隔离级别

1.读未提交
	可能出现脏读(读到了未提交的数据),不可重复度(前后两次读取数据不一致),幻读(第一次读的时候没有查询到数据,但是插入的时间发现已经有了相同的数据)
2.读已提交
	可能出现不可重复读,幻读的情况
3.可重复度
	只会出现幻读的情况
4.可串行化
	最高的隔离级别,可能会出现大量的超时现象和锁竞争情况
	通过强制事务排序,使之不可能相互冲突,从而解决幻读问题,他是在每个读的数据上加上了共享锁

eadLocal.set()源码
public void set(T value) {
//同样获取当前线程
Thread t = Thread.currentThread();
//获取当前线程的map
ThreadLocalMap map = getMap(t);
if (map != null)
//以当前线程为key放入到map集合中
map.set(this, value);
else
createMap(t, value);
}


### 35.获得类对象的3种方法

~~~java
//1.通过类名.class获得
Class c = 类名.class;
//2.通过类的对象.getClass()获得
Student stu = new Student();
Class c = stu.getClass();
//通过Class.forName("类的全限定名")
Class c = Class.forName("类的全限定名");

36.数据库的隔离级别

1.读未提交
	可能出现脏读(读到了未提交的数据),不可重复度(前后两次读取数据不一致),幻读(第一次读的时候没有查询到数据,但是插入的时间发现已经有了相同的数据)
2.读已提交
	可能出现不可重复读,幻读的情况
3.可重复度
	只会出现幻读的情况
4.可串行化
	最高的隔离级别,可能会出现大量的超时现象和锁竞争情况
	通过强制事务排序,使之不可能相互冲突,从而解决幻读问题,他是在每个读的数据上加上了共享锁
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值