后台开发知识点总结(三)Java并发

进程与线程的区别是什么?

进程就是一段程序的执行过程(狭义)。是一个具有特定功能的程序关于某个数据集合运行的一次运行活动,是操作系统分配资源的最基本单位(广义)。线程也称轻量级进程,是程序执行流的基本单元。在引入线程的操作系统中,一般都是把进程作为分配资源的基本单位,把线程作为独立运行和独立调度的基本单位。

主线程退出会导致整个进程退出么?

不一定。Java 中的 Thread 分为User Thread 和 Demon Thread(守护线程)。守护线程与用户线程的区别就在于,如果虚拟机中的线程都是守护线程的话,虚拟机(也就是进程。在java中,每个进程对应一个java虚拟机)将会退出。因此,在主线程退出的时候,如果虚拟机中还有其他的用户线程,虚拟机不会退出。否则,虚拟机中其他的线程都是守护线程,虚拟机将会退出。

守护线程和守护进程的区别是什么?

在一般情况下,当进程的控制终端被关闭的时候,进程会被强行关闭。守护进程是一种能够脱离于终端在后台运行的一种进程。它从被执行的时候开始运转,直到整个系统结束才退出。
守护线程跟一般意义上的线程(用户线程)的唯一区别在于,如果虚拟机中的线程都是守护线程的话,虚拟机(也就是进程)将会退出。
所以说,守护进程的“守护”跟守护线程的“守护”并不是相同的概念。

如何创建守护进程?

1.创建子进程fork(),父进程退出exit();
创建子进程后父进程退出,会导致子进程成为孤儿进程。孤儿进程将会被系统中的1号进程(init)所收养。这样。原来的子进程就变为了init进程的子进程。
2.在子进程中调用setsid();
setsid() 的作用是创建一个新的会话组,并担任新会话的组长。这样做可以使子进程脱离原来的终端、进程组和会话(一个进程组包含一个或多个进程,一个会话包含一个或多个进程组,通常把一个用户从登录到退出过程中,他运行的所有进程归于一个会话)。
3.改变根目录为当前目录chdir();
4.重设文件权限掩码umask();
使用umask()函数将当前进程的umask(当前进程所创建文件的初始权限掩码)置为0。
5.关闭文件描述符;
关闭不需要的文件描述符。

孤儿进程和僵尸进程的区别?

孤儿进程指的是父进程结束而子进程没有结束,而僵尸进程指的是子进程结束而父进程没有wait(或waitpid)它。

僵尸进程的危害与清除?

僵尸进程既不占用内存,也不占用cpu。但是它占用了一个进程号,系统所能够使用的进程号是有限的,因此僵尸进程大量地占用进程号将会导致无法生成新的进程。
清除僵尸进程的方法是:kill产生僵尸进程的父进程。这样僵尸进程就会变成孤儿进程,然后被内核回收。

怎么防止僵尸进程的出现?

1.通过父进程使用 wait() 或 waitpid() 等待子进程,这会导致父进程被挂起。(不过waitpid() 提供了一个无阻塞的wait(),只要把参数设置成 WNOHANG 就行了)。
2.用 signal() 函数为SIGCHLD 安装handler,子进程结束后,父进程会收到信号,可在 handler 中回收。
3.用 signal(SIGCHLD,SIG_IGN) 通知内核,由内核代为回收。
4.先创建子进程,再创建孙进程,创建结束之后杀死子进程,孙进程就会被 init 收养,由 init 回收。

僵尸进程会造成内存泄漏吗?

不会。内存泄漏指的是动态分配的内存空间,使用完之后未被释放。僵尸进程是不占用内存的(准确地说,是不占用java虚拟机的内存),就更谈不上内存泄漏了。

什么叫线程安全?

线程安全指的是在多线程环境下,程序执行的结果与各个线程的调度顺序无关。

使用线程池的好处?

一方面,使用线程池可以减小在创建和销毁线程时产生的时间开销和资源开销(因为在新任务到来时,不必再销毁和新建线程了)。另一方面,使用线程池可以管理线程,保证系统不会因为大量并发产生的资源不足而崩溃。

列举一下你所知道的线程池?

单线程线程池(NewSingleThreadExecutor)、固定数量的线程池(NewFixedThreadExecutor,达到最大数量后线程进入等待队列)、可缓存线程池(NewCachedThreadExecutor,自动回收60s未执行的线程)、大小无限制线程池(NewScheduleThreadExecutor)。

使用线程池的坏处是什么?

使用线程池可能带来额外的风险,比如:
线程池特有的死锁:所有线程都在阻塞等待某一任务的执行结果,而这一任务却因为没有线程而得不到执行。
资源不足:如果线程池太大可能引起不必要的资源浪费。
线程泄漏:有些线程被使用之后可能并不会返回线程池(比如等待某些资源或者用户输入),发生这种情况后线程池中可用线程数会减少。最后变得没有线程可以使用。  

后台开发知识点总结(二)JVM虚拟机

Java类加载过程?

加载:类中的方法被放到方法区、堆中生成一个对象表示该类、
链接:验证(保证符合jvm规范,防止安全问题)、准备(为类变量(静态变量)分配内存,分配的内存在方法区中)、解析(将虚拟机常量池中的符号饮用转变为直接引用)
初始化:执行类构造器方法、如果父类未初始化,先初始化父类。

有几种类加载器?

引导类加载器(Bootstrap Class Loader,加载Java核心库)、扩展类加载器(Extensions Class Loader,加载Java扩展库)、应用程序类加载器(Application Class Loader,加载 Class Path 下的应用程序类)、自定义类加载器(主要是为了加密解密某些类的字节码)。

什么时候触发GC?

JavaGC分为两种,一种是ScavengeGC,另一种是FullGC。前者只对年轻代进行回收,后者对整个堆进行回收(包括年轻代、老年代和持久代)。
当Eden申请内存失败时,触发ScavengeGC。
当老年代(Tenured)被写满、持久代(Perm)被写满、System.gc() 被显示调用以及上一次GC之后Heap各域分配策略出现变化时,触发FullGC。

GC有几种算法?

引用计数法(已弃用)、标记清除法、标记复制法(survivor区)、标记压缩法(老年代)、分代回收法。

Java的垃圾收集器都有哪些?

Serial收集器(串行收集器)、Parallel 收集器(并行收集器)、CMS收集器(并发收集器)、G1收集器。

G1回收器的特点?

空间整合(G1采用标记压缩算法,不会出现分配大对象没有连续空间的情况)和可预测停顿(长度为 M ms的时间内,垃圾收集的时间不得超过 N ms)。

CMS收集器的特点?

并发收集、低停顿。但是会产生内存碎片(标记清除法),每进行几次 GC 就要进行一次碎片整理。

后台开发知识点总结(一)java基础

Java八种基本数据类型:

byte、short、int、long、float、double、boolean、char。

Map在Java中的四种实现?

HashMap(最简单实现)、HashTable(线程安全)、LinkedHashMap(可顺序访问)、TreeMap(基于红黑树实现的map)。

List在Java中的三种实现?

ArrayList(数组)、LinkedList(链表)、Vector(线程安全的ArrayList)。

Set在Java中的四种实现?

HashSet(由HashMap支持,相当于没有 value 的 HashMap) 和 LinkedHashSet(顺序访问)。

Java8的新特性

Lambda表达式:允许把函数作为参数传进方法中。
Stream:random.ints().limit(10).forEach(System.out::println);
Optional类:使用Optional类可以避免显式进行空值检测
Nashorn:Java中调用Js,JavaScript引擎。
方法引用:通过方法的名字指向一个方法(使用::)。
函数式接口:增加了java.util.function函数接口,用来支持函数式编程(支持闭包)
默认方法:接口可以通过defult实现默认方法。
新的日期时间API。
Base64:一种编解码器。

什么是Java NIO?

NIO就是非阻塞IO。

NIO的实现原理是什么?

NIO使用双向的通道(channel)而非单向的流(stream)进行通信。在通道上我们可以注册总共四种事件:客户端连接、服务端接收客户端连接、读、写。客户端和服务端各自维护一个管理通道的对象(selector),接收一个或多个通道的事件。

为什么要用NIO?

对阻塞式IO而言,每一个客户端都要有一个对应的线程来进行处理。每个线程都要占用一些空间和CPU时间。另外,多个线程带来频繁的上下文切换,而这些切换很可能是无意义的。