JAVA-知识汇总

1 javaSE基础

1.1 前言

1. 面向对象

面向对象是一种程序设计技术,他将重点放在数据(即对象)和对象之间的接口上。

2. 可移植性

Java代码或字节码,二进制码可以跨平台的移植,而不用管具体的操作系统与硬件环境。主要依托的JRE运行环境,“一次编写,随处运行”。

3. 高性能

JIT(just in time)即时编译。将一些热点字节码比那已成本地机器码,并将结果缓存起来,在需要的时候重新调用。这样,java程序的执行效率大大提高。

4. 分布式

Java是为internet的分布式环境设计的,因为它能够处理tcp/ip协议。事实上,通过url访问一个网络资源和访问本地文件是一样简单的。java还支持远程方法调用,是程序能够通过网络调用方法。

5. 动态性

就是在需要时将某些代码添加到正在运行的程序中。例如:反射机制等。当需要把某些代码添加到正在运行的程序中时,动态性是一个非常重要的特性。java 的动态性时其面向对象设计方法的扩展。它允许程序动态地装入运行过程中所需要的类。

6. 多线程

多线程的使用可以带来更好的交互响应和实时行为。多线程的简单性是java成为主流服务器开发语言的主要原因之一。

7. 安全性

java适用网络/分布式环境,为了达到这个目标,在安全性方面投入很大精力,使Java可以构建病毒,防篡改系统。

8. 健壮性

吸收了c、c++语言的有点,去掉了影响程序健壮性的部分(如:指针,内存申请与释放等)。java程序不可能造成计算机崩溃。java系统仔细检查对内存的每次访问,确认它是合法的,而且不至于引起任何问题。不过,即使java程序也有可能出现错误,如果出现某种意料之事,程序也不会崩溃,而是把该例外抛弃。再通过异常处理机制,程序就会发现这类例外,并加以处理。

1.2 Java应用程序运行机制

计算机的高级编程语言类型:编译型,解释型。

Java是这两种类型的结合:

1. 利用编辑器写Java源程序,源文件命:主类名.java

2. 利用编译器 javac 将源程序编译成字节码,字节码文件名:源文件名.class

3. 利用虚拟机(解释器)解释执行,运行过程:载入、代码校验、解释执行

整体运行过程:jdk(开发机制)->jre(运行环境)->jvm(虚拟机)

1.3 内存分析

1.3.1 jvm(虚拟机)

        jvm(Java virtual machine)是一种规范,可以使用软件来实现,也可以使用硬件来实现,就是一个虚拟的用于执行bute codes字节码的计算机。也定义了指令集、寄存器集、结构栈、垃圾收集堆及内存区域。

        jvm负责将Java字节码解释执行,边解释便执行,这样速度就会受到一定影响。Java提供了另一种解释运行的方法JIT(just in time),可以一次解释完。在运行特定平台上的机器码,高级的JIT可以只分析内存中调用,这样就大大提供了执行java代码的效率。这样就实现了跨平台、可移植的功能。

        jvm是指一台计算机上由软件或硬件模拟的计算机,类似于一个小巧而高校的cpu。

        byte-code代码是与平台无关的虚拟机的机器指令。

        Java字节码运行的两种方式:

        1. 解释(interpreter)执行

        2. JIT(即时编译):由代码生成器将字节码转换成本机的机器码,然后可以以较高的效率执行。

        不同的操作系统又不同的虚拟机。java 虚拟机制屏蔽了底层运行平台的差异,实现了“一次编译,随处运行”

        Java运行环境三项主要功能:

        1. 加载代码:由class cloader 完成(双亲委派机制)

        2. 校验代码:由bytecode verifier完成

        3. 执行代码:由runtime interpreter完成

        jvm内存结构分析:

jvm深入理解:JVM(11)—— 带你深入理解JVM - xu_shuyi - 博客园

jvm垃圾收集器机制:深入理解JVM垃圾收集机制(JDK1.8) - Ryan.Miao - 博客园

 1.3.2 如何减少FullGC次数

1. 在服务器捏村允许的情况下,尽量提高对内存大小设置。

2. 排查内存泄漏的问题,比如集合种的对象没办法被回收(可以将堆信息dump到文件中,通过mat工具排查存在内存泄漏的情况)

3. 调整年轻代的内存比例,尽量保证对象在年轻代就回收,而不是晋升到老年代。

4. 调整元空间大小。

排查cpu飙升的解决办法:CSDN

1.3.3 jmm内存模型

深入理解JVM-内存模型(jmm)和GC - 简书

1. volatile

JVM(10)——Volatile关键字 - xu_shuyi - 博客园

都知道volatile保证了内存可见性。

内存屏障和volatile什么关系?上面的虚拟机指令里面有提到,如果你的字段是volatile,Java内存模型将在写操作后插入一个写屏障指令,在读操作前插入一个读屏障指令。这意味着你对一个volatile字段进行写操作,你必须知道:1、一旦你完成写入,任何访问这个字段的线程将会得到最新的值。2、在你写入前,会保证所有之前发生的事已经发生,并且任何更新过的数据值也可见的,因为内存屏障会把之前的写入值都刷新到缓存。

2. aqs

Java技术之AQS详解 - 简书

1.3.4 类加载机制

        class loader类加载器,主要的作用是将通过javac 编译后的class文件加载到jvm内存中。jvm启动的时候,并不是一次性加载所有的类,而是根据需要动态的加载类,主要分为隐式加载和显示加载。

        隐式加载:程序中不需要调用class loader来加载所需要的类,而是通过jvm自动加载所需要的类到内存中。例如,当我们在类中继承或者引用某个类的时候,jvm在解析这个类的时候,发现引用的类不在内存中,那么就会自动将这些类加载到内存中。

        显示加载:代码通过class.forName();this.getClass.getClassLoader.LoadClass(),自定义类加载器中的findClass()方法等。

        类加载器模式-双亲委派机制:

        例如:当jvm需要找到Test.class的时候。

        1. 首先会到自定义类加载器中查找,看是否已经加载过,看是否已经加载,则返回字节码。

        2. 如果自定义加载器没有加载过,则询问上一层加载器ApplicationClassLoader是否已经加载过Test.class

        3. 如果没有加载,则继续询问上一层加载器ExtentionClassLoader是否已经加载过。

        4. 如果还没有加载,则继续询问上一层加载器BootStrapClassLoader是否已经加载过。

        5. 如果BootStrapClassLoader依然没有加载过,则到自己指定的类加载路径下,查看是否有Test.class字节码文件,有则返回,没有通知下一层加载器ExtentionClassLoader到自己指定的类加载路径下(Java.ext.dirs)查看

        6. 依次类推,最后到自定义类加载器指定的路径下还没有找到Test.class字节码文件,则跑出ClassNotFundException

如果自定义类加载器:

1. 继承classLoader

2. 重写findClass方法

3. 调用defindClass方法

为什么需要自定义类加载器:

        加密,对字节码进行加密,Java的类文件可以很容易被反编译,为了提高安全性,我们在编译的时候可以加入加密算法,改变二进制文件的编码,然后再定义专门的类加载器加密后文件,在加载之前解密二进制字节码,再加载,这样就可以提高安全性。

        以非标准的方式加载类文件。比如,我们的类文件存放在数据库,ftp,或者从某个网站上下载。

        在运行时候动态的去系统外部加载运行一个类。

        在同一个应用中,通过类加载器实现环境或者资源的隔离。

        通过类加载器实现灵活的可插拔机制。

1.4 基础语法

1.4.1 数据类型

基本数据类型

类型

占用存储空间(字节)

表数范围

整数型->字节型

Byte

1

-128~127

整数型->短整型

Short

2

-2的15次方~2的15次方-1

整数型->整型

Int

4

-2的31次方~2的31次方-1

整数型->长整型

Long

8

-2的63次方~2的63次方-1

浮点型->单精度

Float

4

-3.403E38~3.403E38

浮点型->双精度

Double

8

-1.798E308~1.798E308

字符型

Char

2

布尔型

Boolean

1位

补充:

float单精度,尾数可以精确到7位有效数字,很多情况下,float类型精度很难满足业务需求。

double双精度,尾数可以精确到float的2倍,绝大部分应用程序都采用double类型。

大数值:

Java.math 下面有两个有用的类:biginteger,bigdecimal,这两个类可以处理任意长度的数值。biginteger实现了任意精度的整数运算,bigdecimal实现了任意精度的浮点运算。

引用数据类型(类class,接口interface,数组)大小统一为4个字节,记录的是其引用对象的地址。

1.5 面向对象

面向对象变成的三大特征:封装,继承,多态。

1.5.1 封装

我们程序设计追求:高内聚,低耦合。高内聚,就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合,仅暴露少量的方法给外部使用。

意义:

便于调用者调用

便于修改内部代码,提高可维护性

可进行数据完整性检测,保证数据有效性

1.5.2 继承

优点:

继承的本质在于抽象,类是对对象的抽象,继承是对某一批类的抽象,从而实现对现实世界更好的建模。为了提高代码的复用,子类是父类的扩展。

要点:

1. 子类继承父类,可以得到父类的全部属性和方法(除了父类的构造方法)。

2. 类只有单继承,接口可以实现多继承。

3. 实例化一个类是从最顶级的超类开始实例化的,是一层一层的包裹结构。

4. object类是所有类的根基类,也就是说,类默认是继承object类,所有当前类可以使用object类中定义的很多方法,像toString,equals等。

5. 继承涉及对父类方法的重写,重写方法必须和重新方法具有相同的方法名称,参数列表,返回类型。

1.5.3 多态     

如何实现多态:

引用变量的两种类型

1. 编译时类型(由声明时的类型决定)

2. 运行时类型(运行时,具体时那个子类就是哪个子类)

多态,如果编译时类型和运行时类型不一致,就会造成多态。

多态时oop中的一个重要特性,主要是用来实现动态联编的,换句话说,就是程序的最终状态只有在执行过程中才被决定而非在编译器就决定了。这对于大型系统来说能提供系统的灵活性和扩展性。

要点:

多态是方法的多态,属性没有多态。

多态存在的3个必要条件:继承,重写,父类引用指向子类对象。

1.5.4 抽象类

要点:

        不能实例化,不能通过new来实例化抽象类。

        抽象类可以包含属性,方法,构造方法。但是构造方法不能用来new实例,只能用来被子类调用。

        只能用来继承

        抽象方法必须被子类实现

        实现了规范和具体实现的分离。通过abstract方法定义规范,然后要求子类必须定义具体实现。引用仍然可以定义为抽象类,这样就可以规范地实现多态了。

为什么需要接口,接口和抽象类之间的区别?

        接口就是比 抽象类 还抽象的 抽象类,可以更加规范的对子类进行约束。全面地专业地实现了:规范和具体实现的分离。

        抽象类还提供某些具体实现,接口不提供任何实现,接口中所有方法都是抽象方法。接口是完全面向规范的,规定了一批类具有的公共方法规范。

        接口时两个模块之间的通信标准,通信的规范。

如何定义接口?

访问修饰符,只能时public或默认。

接口名,和类名采用相同命名机制。

extends,接口可以实现多继承。

常量,接口中的属性只能是常量,总是public static final修饰,不写也是。

方法,接口中的方法只能是public abstract,省略的话也是。

内部类

一般情况,我们把类定义为独立的单元。有些情况下,我们把一个类放在另一个类的内部定义,成为内部类。

作用:

1. 内部类提供了更好的封装,只能让外部类直接访问,不允许同一个包中的其他类直接访问。

2. 内部类可以直接访问外部类的私有属性,内部类被当成其外部类的成员,但外部类不能访问内部类的内部属性。

1.6 异常机制

Java 是采用面向对象的方式类处理异常的。

处理过程:

1. 抛出异常,在执行一个方法时,如果发生异常,则这个方法生成代表该异常的一个对象,停止当前执行路径,并把异常对象提交给jre。

2. 捕获异常,jre得到异常后,寻找相应的代码来处理该异常。jre在方法的调用栈中查找,从生成异常的方法开始回溯,直到找到相应的异常处理代码为止。

异常分类:

error:

error类层次描述了java运行时系统内部错误和资源耗尽错误。 这类错误我们无法控制,同时也是非常罕见的错误,所以在编程中,不去处理这类错误。

error表明系统jvm已经处于不可恢复的崩溃状态中。

exception:

所有异常类的父类,其子类对应了各种各种的可能出现的异常事件。

runtimeexception:

出现 runtime exception 就一定是你的问题,可以不捕获,因为小心点这些异常时可以避免的。

常见的:

1. arithmetic exception 数学异常

2. null pointer exception 空指针异常

3. classcast exception 类转换异常

4. array index outofbounds exception 数组下标越界异常

5. numberformat exception 数字格式化异常

try catch finally return 执行顺序:

1. 执行try catch,给返回值赋值

2. 执行finally

3. return

考察关于finally:

如果try中return,那么finally是在return 之前执行,还是return 之后执行呢?

正确答案:之后。

如果try中return,那finally中也有return,会出现什么样的结果?

正确答案:返回finally中的return的结果。

1.7 数组

相同类型数据的有序集合,数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成。其中,每一个数据称作为一个数组元素,每个数组元素可以通过一个下标来访问它们。

基本特点:

1. 长度确定,数组一旦创建,它的大小就是不可以改变的。

2. 元素必须是相同类型,不允许出现混合类型。

3. 数组中的元素可以是任何数据类型,包括基本类型和引用类型。

4. 数组变量属于引用类型,数组本身就是对象,java中对象是在堆中,因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中的。

数组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式隐式初始化。

1.8 常用类

1.8.1 String

new String("123");创建了几个对象?

正解:new string(abc)创建了几个对象_面试题系列第2篇:new String()创建几个对象?有你不知道的..._田小圣的博客-CSDN博客

1.9 容器

collection 表示一组对象,它是集合,收集的意思,就是把一些数据收集起来。

1.9.1 层次结构

1. list 接口

有序的collection,此接口的用户可以对列表中每个元素的插入位置进行精确的控制。用户可以根据元素的整数索引访问元素,并搜索列表中的元素。

linkedList:底层双向列表实现。特点:查询效率低,增删效率告,线程不安全。

arrayList:底层数组实现。特点:查询效率告,增删效率低,线程不安全。

vector:底层数组实现。特点:线程安全。

2. set 接口

hashSet:采用哈希算法实现的set。

hashSet的底层使用hashmap实现的,因此查询效率高。由于采用hashcode算法直接确定元素的内存地址,增删效率高。

3. map接口

实现map接口的类用来存储kv对。

map接口的实现类有hashmap,treemap等。

map类存储的键值对来标识,所以键值不能重复。

hashmap:线程不安全,效率高,允许k,v为null。

hashtable:线程安全,效率低,不允许k,v为null。

4. iterator接口

所有实现了collection接口的容器类都有一个iterator方法用以返回一个实现了iterator接口的对象。

iterator对象称为迭代器,用以方便的实现对容器内元素的遍历操作。

1.9.2 equals hashcode

hashcode 并不是内存地址,而是内存地址转换而来的。系统通过它可以确定内存地址。

hashcode方法主要用在集合框架中,目的是为了快速比较两个对象是否相等,因为集合框架中的对象很多,每个都是用equals比较效率很差。

每个对象都有一个hashcode,规定:

1. 内容相同的对象,hashcode肯定相等。

2. 内容不相等的对象,hashcode可能相等。

所以如果两个对象hashcode不相等,则两个对象的内容肯定不相等,这样就不必一个一个去比较属性的值了,从而提高对象比较的速度。

1.9.3 hashmap

面试题(5)--HashMap? ConcurrentHashMap? 相信看完这篇没人能难住你! - xu_shuyi - 博客园

1.10 IO流

1.10.1 流概念

输入流:数据源到程序(inputstream,reader 读进来)

输出流:程序到目的地(outputstream,writer 写出去)

处理数据单元:

字节流:按照字节读取数据(inputstream、outputstream)

字符流:按照字符读取数据(reader、writer)

功能不同:

字节流:可以直接从数据源或目的地读取数据

处理流:不直接连接到数据源或目的地,是处理流的流。通过对其他流的处理提高程序的性能。

注:

字节流和处理流的关系:

字节流处于io操作的第一栈,所有操作必须通过它们进行;处理流可以对节点流进行包装,提高性能或提高程序的灵活性。

1.10.2 四个io基本抽象类

1. inputstream

此抽象类是标识字节输入流的所有类的超类。inputstream 是一个抽象类,它不可以实例化。数据的读取需要又它的子类来实现。根据节点的不同,它派生了不同的节点流子类。

2. outputstream

此抽象类是标识输出字节流的所有类的超类。输出流接收输出字节并将这些字节发送到某个接收器。

3. fileinputstream

用于读取诸如图像数据之类的原始字节流。要读取字符流,请考虑使用filereader。

4. fileoutputstream

用于写入诸如图像数据之类的原始字节的流。要写入字符流,请考虑使用filewriter。

1.10.3 Java对象的序列化和反序列化

当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论何种类型的数据,都会以二进制的形式在网络上传送。发送方需要把这个java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为java对象。

只能将支持java.io.serializable接口的对象写入流中。每个serializable对象的类都被编码,编码内容包括类名和类签名、对象的字段值和数组值、一级从初始对象中引用的其他所有对象的闭包。

把java对象转换为字节序列的过程称为对象的序列化。把字节序列恢复为Java对象的过程称为对象的反序列化。

对象序列化主要用途:

1. 持久化

把对象字节序列永久保存在硬盘上,通常存放在一个文件中。

2. 网络通信

在网络上传送对象的字节序列。比如,服务器之间的数据通信。

对象序列化基本原理:

序列化API

Java.io.objectoutputstream 代表对象输出流,它的write Object方法可对参数指定的obj对象进行序列化,把得到的字节序列写道一个目标输出流中。只有实现了serializable和externalizable接口的类对象才能被序列化。

Java.io.objectinputstream 代表对象输入流,它的readObject方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。

说明:

1. 读取对象的顺序与写入对象的顺序要一致。

2. 对象的默认序列化机制写入的内容:对象的类、类签名、以及非瞬时态transient和非静态static 字段的值。

序列化实现方式:

1. 通过实现serializable接口操作。

2. 通过实现externliable接口操作,只是这种操作需要实现writeExternal及readExternal方法,我们将一个对象进行序列化,然后再反序列化之后,发现对象的属性恢复成了默认值,也就是说之前的那个对象的状态并没有持久化下来,这就是externalizable和serializable的区别。

Externalizable继承了Serializable,该接口中定义了两个抽象方法:writeExternal()与readExternal()。当使用Externalizable接口来进行序列化与反序列化的时候需要开发人员重写writeExternal()与readExternal()方法。由于上面的代码中,并没有在这两个方法中定义序列化实现细节,所以输出的内容为空。还有一点值得注意:在使用Externalizable进行序列化的时候,在读取对象时,会调用被序列化类的无参构造器去创建一个新的对象,然后再将被保存对象的字段的值分别填充到新对象中。所以,实现Externalizable接口的类必须要提供一个public的无参的构造器。

注意:

对象序列化时,并不保存静态变量,这其实比较容易理解,序列化保存的是对象的状态,静态变量属于类的状态,因此 序列化并不保存静态变量。

Transient 关键字的作用是控制变量的序列化,在变量声明前加上该关键字,可以阻止该变量被序列化到文件中,在被反序列化后,transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。

1.11 多线程

1.11.1 进程

执行中的程序叫做进程 process,是一个动态的概念。

进程是程序的一次动态执行过程,占用特定的地址空间。

每个进程由3部分组成:cpu、data、code。每个进程都是独立的,都有自己的cpu时间,代码和数据。

多任务操作系统,将cpu时间动态的划分为每个进程,操作系统同时执行多个进程,每个进程独立运行。

1.11.2 线程

线程是进程中一个 单一的连续控制流程。线程也可以达到同一份程序产生好几个进程的效果,但是不同的线程之间可以有某种程度上的资源共享,所以线程又称为轻量级进程。

一个进程可拥有多个并行的线程。

一个进程中的线程共享相同的内存单元、内存地址空间。

1.11.3 线程和进程区别

每个进程都有独立的代码和数据空间(进程上下文),进程间切换会有较大的开销。

线程可以堪称轻量级的进程,同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(pc),线程切换的开销小。

线程和进程最根本的区别在于:进程是资源分配的单位,线程是调用和执行的单位。

多进程:操作系统中能同时运行多个任务。

多线程:同一个应用程序中有多个顺序流同时执行。

线程是进程中的一部分,所以线程有时候被称为轻权进程或者轻量级进程。

1.11.4 进程和程序的区别

程序是一组指令的集合,它是静态的实体,没有执行的含义。而进程是一个动态的实体,有自己的生命周期。一般来说,一个进程肯定与一个程序相对应,并且只有一个,但是一个程序可以有多个进程,或者一个进程都没有。除此之外,进程还有并发性和交往性。简单的说,进程是程序的一部分,程序运行的时候会产生进程。

1.11.5 实现多线程方式

1. 继承thread

这种方式的确定,由于类是单继承,如果类已经从一个类继承,则再也无法进行tread类。

2. 实现runnable

可以同时实现继承,相较thread,实现runnable 比较通用。

1.11.6 线程状态

1. 新生状态

用new关键字和thread类或其子类建立一个线程对象后,该线程对象就处于新生状态。处于新生状态的线程有自己的内存空间,通过调用start方法进入就绪状态。

2. 就绪状态

处于就绪状态的线程已经具备了运行条件,但还没有分配到cpu,处于线程就绪队列,等待系统为其分配cpu。一旦获得cpu,线程就进入运行状态并自动调用自己的run方法。

3. 运行状态

在运行状态的线程执行自己的run方法中代码,直到调用其他方法而终止、或等待某资源而阻塞或完成任务而死亡。如果在给定的时间片内没有执行结束,就会被系统给换下来回到等待执行状态。

4. 死亡状态

死亡状态是线程生命周期最后一个阶段。线程死亡的原因有两个,一个是正常运行的线程完成了它的全部工作;另一个是线程被强制性终止,如通过执行stop或者destroy方法来终止一个线程。

5. 阻塞状态

在阻塞状态的线程不能进入就绪队列。只有当引起阻塞的原因消除时,如睡眠时间已到,或等待I/O设备空闲下来,线程便转入就绪状态,重新到就绪队列中排队等待,被系统选中从原来停止的位置开始继续运行。

sleep:sleep时,别的线程也不可以访问锁的对象。

yield:让出cpu使用权,从运行态直接进入就绪态,让cpu重新挑选哪一个线程进入运行状态。

join:当某个线程等待另一个线程执行结束后,才继续执行,使用join方法。使调用该方法的线程在此之前执行完毕,也就是等待调用该方法的线程执行完毕后再往下继续执行。

6. 等待(阻塞)状态

wait 的作用使让当前状态进入等待状态,同时,wait也会让当前线程释放它所持有的锁。直到其他线程调用此对象的notify或者notifyall,当前线程被唤醒,进入就绪状态。

notify,notifyall的作用,则使唤醒当前对象上的等待线程。notify是唤醒单个线程,notifyall是唤醒所有线程。

wait让当前线程处于等待状态,直到其他线程调用此对象的notify,notifyall方法,或者超过指定的时间量,当前线程被唤醒,进入就绪状态。

Java 提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程。线程调度器按照线程的优先级决定应调度哪个线程来执行。

线程的优先级用数字来表示:范围 1,10

注意:优先级低只是意味着获得调度的概率低,并不是绝对先调用优先级高后调用优先级低的线程。

1.11.7 死锁及解决

往往是程序逻辑问题,尽量不要同时持有两个对象。

1.11.8 线程池

/**
 * 固定线程池测试
 */
private static void newFixThreadPoolTest() {
    Integer fixThreads = 2;
    ExecutorService executorService1 = Executors.newFixedThreadPool(fixThreads);

    MyThread myThread1 = new MyThread();
    MyThread myThread2 = new MyThread();


    executorService1.execute(myThread1);
    executorService1.execute(myThread2);
    MyThread myThread3 = new MyThread();
    executorService1.execute(myThread3);

    List<Future<MyThread>> futureList = new ArrayList<>(fixThreads);

    for (int i = 0; i < 2; i++) {
        Callable<MyThread> callable = new Callable<MyThread>() {
            @Override
            public MyThread call() throws Exception {
                return new MyThread();
            }
        };

        futureList.add(executorService1.submit(callable));
    }

    for (int i = 0; i < futureList.size(); i++) {
        Future<MyThread> myThreadFuture = futureList.get(i);
        try {
            System.out.println(myThreadFuture.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

    }

    executorService1.shutdown();
}

以上使用一个固定线程池为例,看看线程的任务的创建及回调。

threadpoolexector线程池submit,execute区别:

ThreadPoolExecutor线程池submit() 和 excute()区别_Java小宝的博客-CSDN博客

1.12 网络编程Net

1.12.1 协议

1. TCP

传输数据安全,稳定,效率相对较低。

面向连接,通信必须先建立连接:

1. 请求端(客户端)发送一个包含SYN即同步标志的tcp报文,syn同步报文会指明客户端使用的端口,即tcp连接的初始序号。

2. 服务器在接收客户端的syn报文后,将返回一个syn+ack的报文,表示客户端的请求被接受,同时tcp需要+1,ack即确认。

3. 客户端也返回一个ack确认报文给服务器,同样tcp序号+1,到此一个tcp连接完成。

2. UDP

传输数据不安全,效率较高。

3. 通信连接

1. 创建serverSocket,创建时,定义serverSocket的监听端口

2. serverSocket调用accept方法,使之处于阻塞状态。

3. 创建客户机socket,并设置服务器的ip及端口

4. 客户机发出连接请求,建立连接。

5. 分别取得服务器和客户端socket的inputstream和outputstream

6. 理用socket和serverSocket进行数据传输

1.12.2 dhcp基本原理机实现过程

DHCP基本原理及实现过程_Buster_ZR的博客-CSDN博客_dhcp原理及其实现流程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr_Xu321

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值