文章目录
- 一、java与c的区别
- 二、java的特点
- 三、java是一种跨平台的语言
- 四、面向对象
- 五、面向过程
- 六、常用类
- 七、数组
- 八、异常
- 5.throw
- 九、集合
- 十、IO流
- 十一、HTTP网络编程
- 十二、线程与进程
一、java与c的区别
- java是一门面向对象的语言
- C语言是一门面向过程的语言
- java是跨平台的语言
二、java的特点
- 简单
- 面向对象
- 跨平台
- 支持多线程与网络编程
- 安全性
三、java是一种跨平台的语言
- 跨平台性
- java编写的程序,在一次编译后,可以在多个系统平台上运行
- java程序是通过java虚拟机在系统平台上运行的,只要安装相应的java虚拟机,该系统就可以运行java程序
四、面向对象
1.什么是面向对象
- 我面对你,就是面向对象,
- 面向对象是一种思想,世间万物都是对象.
2.面向对象的特点是什么
- 三大特点
- 封装
- 继承
- 多态
3.封装
(1)什么是封装
封装就是包装,将实现细节包装起来,对外提供方法访问
(2)java中,有4中修饰符是什么?
- public 公共的,可以被任何类访问
- protected 受保护的,不同包必须创建一个子类才能实现
- default 默认的,同包权限,只能访问同种包
- private 私有的,只能在同类中进行调用
(3)封装的优点是什么?
- 提高安全性,提高代码的复用性
- 操作简单
- 降低了耦合性
4.继承
(1)什么是继承?
- 继承就是子类继承父类,子类在具有自己的属性和功能时,还可以改写父类中的方法(方法的重写与多态有关)
(2)继承的优点是什么?
- 提高了父类代码的可重复利用性
- 子类代码的可扩展性
- 继承还具有传递性
(3)继承的缺点是什么?
- 具有入侵性(继承拥有父类的所有非私有的属性和方法)
- 增大了俩个类耦合性(使各个模块的独立性越来越差)
- 父类变,子类变
(4)注:
- 一个字类只能有一个直接父类
5.重写Override
(1)什么时候需要重写?
- 当父类的方法不能满足子类的需求时,就需要子类重写父类的方法
(2)重写是什么?
- 子类的实现与父类的不同时,可以在子类中将父类的方法覆盖
(3)重写的条件是什么?
- 子类的方法结构必须与父类的结构相同
- 子类重写的访问权限必须大于等于父类的访问权限
(4)注:
- 正常类中,若方法中有final,则不能再子类中重写
6.重载Overload
(1)什么是重载?
- 重载就是一个类中有多个名字相同但参数不同的方法.
(2)方法重载的必要条件是什么?
- 参数的数量不同
- 参数的类型不同
- 参数的顺序不同
(3)注:
- 方法的重载与返回值无关
- 且调用时会根据参数的不同而调用不同的方法
7.多态
(1)什么是多态?
- 多态就是同一种事物,在不同的时刻的不同的状态
(2)多态的条件是什么?
- 要有继承
- 有方法的重写
- 父类的引用 指向 子类的对象
(3)多态的优点是什么?
- 提高了代码的维护性
- 提高了代码的可延展性
(4)多态的缺点是什么?
- 不能使用子类的特有功能
(5)多态的最大特点是什么?
- 编译看左边,运行看右边
8.抽象类
(1)什么是抽象类?
- 被abstract修饰的类就叫做抽象类
(2)什么时候使用抽象类?
- 在顶层中实现的方法大多数与子类方法不相同,在顶层中就可以吧方法声明为抽象方法
- 被abstract所修饰,没有方法体
- 只作为方法的定义
(3)抽象类的优缺点是什么?
- 优点:
- 在顶层中实现的方法大多数与子类方法不相同,在顶层中就可以吧方法声明为抽象方法
- 当一个类中加入了一个非抽象方法时,所有的子类都可以改方法
- 缺点:
- 当一个抽象类中加入了一个抽象方法时,所有的子类都必须实现新的抽象方法
(4)注:
- 抽象类中不一定有抽象方法
- 有抽象方法的一定是抽象类
- 一个类继承抽象类
- 要么将子类继续声明为抽象类
- 要么重写抽象类中所有的抽象方法
9.接口
(1)什么是接口?
- 被interface修饰的就是接口
(2)接口的优缺点是什么?
- 优点:
- 一个类可以实现多个接口,打破了继承的局限性
- 降低了一个程序的耦合性(可以实现模块化开发,定义好开发,每个人实现自己的模块,提高了开发效率)
- 缺点:
- 如果一个接口中加入一个抽象方法时,那么实现这个接口的类都得编写具体的实现
(3)注:
- 接口修饰的成员必须是常量
- 被接口修饰的方法必须是抽象方法,不能有方法体
- 类实现接口必须完善接口里所有的抽象方法
10.接口与抽象类的区别与联系
- 接口与抽象类的区别是什么?
- 接口是用来被实现的,抽象类是用来被子类继承的
- 成员
- 接口没有实现代码的实现,只可以定义常量
- 抽象类中有普通方法,并且可以定义变量
- 修饰符
- 接口的方法修饰符只能是public
- 而抽象类的修饰符可以是public,protected,default
- 构造方法
- 接口中没有构造方法
- 抽象类中可以有构造方法
- 什么时候使用接口?
- 当我们需要一组规范的方法时,我们可以用接口
- 无论是飞机还小鸟,他们都会飞,飞就是一个特性,就可以用接口
- 什么时候使用抽象类?
- 当我们需要模板的时候,可以使用抽象类
- 上帝创造了动物,每个动物都会吃,但是每个动物吃的具体实现是不同的,我们就可以用抽象类
五、面向过程
1.什么是面向过程
- 面向过程是分析出解决问题的过程,在一步一步的实现
2.面向对象与面向过程的区别与联系
- 区别
- 面向对象强调功能的对象,以类或者对象为最小单位考虑谁来完成
- 面向过程强调功能行为,以函数为最小单位,一步一步完成
- 联系
- 面向过程适用于处理简单的事情
- 面向对象适用于处理复杂的事情,先使用面向对象对整体的关系进行分类,在对不同的类进行细节上的处理
- 在面向对象中,对不同的类进行细节处理的时候仍然采用的是面向过程的思维方式.
六、常用类
1.什么是包装类
- 八个和基本数据类型对应的类统称为包装类
2.为什么java有了基本类型后还有包装类
- 因为在面向对象的编程中,基本数据类型不是面向对象的,通常会使用不便,所以对每个基本类型设计了一个包装类
3.什么是装箱,拆箱
- 装箱:
- 自动将基本数据类型转换为包装器类型
- 装箱的时候自动调用的是Integer的valueOf(int)方法
- 拆箱:
- 自动将包装器类型转换为基本数据类型
- 拆箱的时候自动调用的是Integer的intValue方法
//自动装箱
Integer num4 = num3;
//Integer num4 = Integer.valueOf(num3);
//自动拆箱
int num5 = num4;
//int num5 = num4.intValue();
4.Object类
(1)重写toString方法
- public String toString() 返回对象的字符串表示形式。一般情况下子类覆盖次方法。
(2)equals和==的区别
- ==:比较的是两个对象的地址值是否相同,
- equals()方法默认比较的是两个对象的地址值是否相同,
- 如果重写了Object类中的equals()方法,那么默认比较就是两个对象的内容是否相同
- (String类已经对equals()方法进行了重写,所以要比较String的内容是否相同,最好用equals()方法进行比较)
5.String类
(1)String,StringBuffer和StringBuilder的区别
- StringBuilder 内容可变
- StringBuffer 内容可变,线程安全
- String 内容不可变,变了都是重新创建对象
(2)StringBuffer和StringBuilder的区别
- StringBuilder
- 线程不安全
- 线程中一个操作,没什么事情,那如果多个线程同时进行操作呢
- StringBuffer
- 线程安全 (因为在底层加了synchronized锁)
- 会对其排序一个线程一个操作 所以效率会低一点儿
6.Arrays类
1.sort()方法
- 一般要继承并实现Comparable接口,重写compareTo()
- public static void sort(int[] a):按照数组顺序排列指定的数组。
- Arrays.sort():
- 数组中的元素数量大于286 使用归并排序算法
- 数组中的元素数量小于47使用插入排序算法
- 数组元素数量>47 <286 使用快速排序算法
七、数组
1.什么是数组?
- 数组(Array)是相同数据类型元素的集合,数组本身也是引用数据类型(对象),是一种线性结构的数据结构.
2、数组的特点是什么?
- 数组是有序排列的
- 每个元素都有下标
- 可以快速查找
- 但是从中间添加,删除就比较麻烦
- 数组中可以存储基本类型,也可以存储引用类型
- 数组本身属于引用数据类型,但是数组的元素既可以是基本数据类型,也可以是引用数据类型
- 创建数组对象会在内存中开辟一整块连续的空间,而数组名引用的是这块连续空间的首地址
- 数组的长度一旦确定,就不能更改
3.如何创建数组
//创建一个数组
int [] a;//简单创建法
int b [];
int[] c = {1,2,3,4,5,6};//赋值创建法
String[] str = new String[5]//表明数组长度创建法
4、如何遍历数组?
-
数组的索引从 0 开始,到数组长度 - 1 为止
-
for循环遍历
int[] ids = new int[10]; for(int i = 0;i < ids.length;i++){ System.out.println(ids[i]); }
-
增强for循环遍历
int[] ids = new int[10]; for(int id : ids){ System.out.println(id); }
5.增强for的优缺点是什么?
- 缺点:
- ①增强for不能动态的(迭代的)给数组赋值;
- ②增强for不能逆向遍历数组;
- ③增强for循环遍历时不能有删除和添加操作(对于map等集合而言,因为在增强for遍历之前就已经锁定了集合)
- 优点:
- ①增强for使用于循环次数未知
八、异常
1.什么是异常
- 异常:在java中将程序执行中发生不正常的情况称为异常
- 异常分为编译时异常和运行时异常
- String a =10 叫做语法错误,不叫异常
- Error异常:虚拟机无法解决的问题
- eg:递归中,值太大,超出虚拟机范围
- Exception异常:编译错误,且程序可以处理的
2.运行时异常
(1)数组越界
int[] a = new int[5];
a[5] = 10;
(2)空指针异常
String a = null;
a.length();
(3)类型转换异常
Object a = "abc";
Integer i = (Integer) a ;
(4)数字格式化异常
new Integer("abc");
(5)算术异常
int a = 10;
int b = 0;
System.out.println(a/b);
3.try-catch
try{
//可能出现异常的代码
}catch(异常类型1 变量名1){
//处理异常的方式一
}catch(异常类型 变量名){
//异常处理方法
}finally{
//一定会执行的代码
}
- catch 中的异常类型,如果没有子父类关系,先后顺序可变,如果满足子父类关系,父类写在下面
- 常用的异常处理方式:String getMessage() printStackTrace()
- 一旦出现异常,就在catch中解决异常,解决后跳出 try-catch
- finally是可选的
- finally中的语句是一定被执行的,即使catch中出=出现异常、try中有return语句、catch中有return语句
4.throws
- throws 定义一个方法的时候可以使用throws关键字声明,表示此方法不处理异常,而交给方法调用处进行处理。
- 任何方法都可以使用throws关键字声明异常类型,包括抽象方法。
- 子类重写父类中的方法,子类方法不能声明抛出比父类类型更大的异常。
- 使用了throws的方法,调用时必须处理声明的异常,要么使用try-catch,要么继续使用throws声明
5.throw
- throw关键字用于显式抛出异常,抛出的时候是抛出的是一个异常类的实例化对象.
- throw用于方法体中,使用后要么使用try/catch捕获异常,要么throws异常.
- 在throw所new的异常方法中一般需要在方法声明处throws异常类型.
- void方法没有返回值,所以一般把可能有异常的代码.主动抛出,让调用方法处理.
6.throws和throw的区别
- 不同点:
- 位置:throws抛出异常在方法声明处且可以有多个异常类型,而throw抛出异常在方法体中
- 修饰对象:throws修饰的是方法名,而throw修饰的对象
- 用到throw一般就会用到throws异常或者try - catch处理。
- 用到thrwos时需要在顶方法中通过try - catch处理。
当throw在方法体中抛出编译期异常时,需要通过throws在方法声明处显示抛出异常。
九、集合
为什么需要泛型
- 早期object可以接受任意对象类型,没有定义类型,默认为Object,存比较方便
- 但是在具体使用时,需要向下转型,则会出现问题
1.集合和数组的区别是什么?
- 集合是用来装东西的,就好像一个容器.
- 数组是一个容器
- 数组的缺点:长度不能改变,只能存储同一种数据
2.java为什么要提供许多集合类来存储数据?
- 1.因为要求集合类的长度是可变的
- 2.不同的数据存储,操作方式不同
- 3.底层有数组,链表,Hash表,树来实现
3.集合的分类
ArrayList底层数组实现
List元素可重复 LinkedList底层链表实现
Vocter底层数组实现线程安全
单列集合 Collection
Set元素不可重复 HashSet底层hash表实现
集合 TreeSet底层红黑树实现
HashMap
双列集合 Map TreeMap
HashTable
4.单列集合collection–(接口)
- set接口:元素不可重复
- 包含:Hashset类(底层由哈希表实现),Treeset类(底层由树实现)
- list接口:元素可重复
- 包含:ArrayList类(数组底层实现),LinedList类(底层链表实现),Vector类(底层链表实现–线程安全)
5.Iterator迭代器接口
- Iterator对象称为迭代器,主要用于遍历Collection集合中的元素、同时也可以在遍历时删除集合中的元素
- Iterator 仅适用于集合遍历
- 集合对象每次调用 iterator()方法都会得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前
6.Collection子接口一:List
- List继承了Collection接口,有三个实现的类
(1)ArrayList
- 数组列表,数据采用数组方式存储。
- 底层数组实现,查询快,增删慢
- 创建之初,在底层创建一个默认长度为10的数组,
- 当数组内容添加满了后,再继续添加时会扩容一个新数组,为原来的1.5倍
- 缺点:扩容后,元素不能存满,空间浪费
(2)LinkedList
- 链表
- 底层是链表实现,查询慢,增删快
- 元素查找时从第一个字节向后查找
- 增加,删除元素时,其他元素位置不动,只需要改变指针域的值即可
(3)Vector
- 数组列表,添加同步锁,线程安全的
- 底层也是数组实现
- 在创建对象时,就已经创建底层存储数组,长度默认为10
- vector中的方法,都是线程安全
- Abstractclist 列表的抽象类
- size()包括一些底层类共有的方法实现
7.Collection子接口二:Set
(1)什么是Set接口
- Set接口是Collection接口的子接口,没有提供额外的方法,使用的都是Collection声明过的方法
- Set集合不允许包含相同的元素
(2)Set接口的特点
- 无序性
- 存储的元素在底层并非按照数组索引的顺序添加,而是根据数组的hash值确定的
- 不可重复性
- 向set中添加元素的过程
- 步骤一:向 HashSet 中添加元素a,首先调用a所在类的hashCode方法,计算hash值,进而通过此hash值通过某种算法计算出该元素在数组中存放的索引值。
- 步骤二:获得索引值后,判断该位置是否有元素,如果此位置没有元素,则添加成功
- 如果此位置有元素,,首先比较a和这个位置元素的hash值
- 如果hash值不同,则元素a添加成功
- 步骤三: 如果hash值相同,则调用a所在类的equals方法,将其他元素传入equals方法的形参
- 如果方法返回true,元素a添加失败
- 如果方法返回false,则添加成功(以链表形式存储)
- 向set中添加元素的过程
(3)treeSet
- 向treeSet中添加的元素必须是同一个类的对象(这样才能比较大小)
- 存储的对象必须实现Comparable接口
(4)HashSet
- HashSet不能存储重复元素
8.Collection子接口二:Map
(1)map的遍历
- 通过keySet()
- 先获取map中所有的健存储到set集合中
- 在对set集合进行遍历,通过每次拿到可以来获取对应的值
(2)map集合的特点
- hashmap
- 健值对存储
- 健不能重复,值可以重复
- 健是无序的,可以存储一个null的健
- TreeMap
- 键值对
- 健不重复
- 可以根据健的自然顺序排序
- 指定健的类型的类必须实现comparabl接口,排序使用
- Hashtable
- 无序的
- 初始容量为11
- 线程安全
- 不允许存储为null的健
十、IO流
- I就是in,从外到里,O就是out,从里到外,流就是stream
- io流就相当于读写数据的一个管道.主要分为输入流和输出流,分别对应读数据和写数据.
1.流的汇总
2.什么是字符流输出,什么是字节流输出?
- printWrite 字符流输出
- printStream 字节流输出
3.IO流怎么读取文件?
- 使用File对象获取文件路径,
- 通过字符流Reader读取文件,
- 使用字符缓存流BufferedReader处理Reader,
- 再定义一个字符串,循环遍历出文件。
4.BufferReader是什么?
- Reader是读,属于字符流,而buffer是缓冲的作用
- 带有缓冲区,所以效率比较高的的读取字符流
5.什么叫对象序列化,什么是反序列化?
- 对象序列化:用 ObjectOutputStream 类将一个Java对象写入IO流中
- 反序列化:用 ObjectInputStream 类将IO流中恢复该Java对象.
6.什么是转换流
- 转换流是处理流的一种,有两个分别是
- InputStreamReader 将一个字节的输入流转化为字符的输入流
- OutputStreamWriter 将一个字符的输出流转化为字节的输出流
十一、HTTP网络编程
1.Http协议是什么?
- 即就是客户端和服务器交互的一种通信的格式。
2.HTTP的作用是什么?
- HTTP的诞生主要是为了让文档之间相互关联,形成超文本可以相互传输。
3.ip,端口号,mac的区别
- IP 地址:InetAddress
- 唯一的标识 Internet 上的计算机
- 就像小区地址一样,全球唯一
- 端口号
- 标识正在计算机上运行的进程(程序)
- 不同的进程有不同的端口号
- 就像门牌号一样,用来认识应用程序(线程)
- mac
- 硬件的唯一表识(客户端)
4.TCP和UDP都是什么?
- TCP(传输控制协议)
- 是面向连接的协议,也就是说,在收发数据前,必须和对方建立可靠的连接。一个TCP连接必须有三次握手,四次挥手。
- UDP(用户数据报协议)
- 是一个面向非连接的协议,传输数据之前源端和终端不建立连接,当它想传送时就简单地去抓取来自应用程序的数据,并尽可能快的把他扔到网上。
5.TCP和UDP的区别是什么?
TCP | UDP | |
---|---|---|
连接性 | 面向连接 | 面向非连接 |
传输可靠性 | 可靠 | 不可靠 |
报文 | 面向字节流 | 面向报文 |
效率 | 传输效率低 | 传输效率高 |
流量控制 | 滑动窗口 | 无 |
拥塞控制 | 慢开始、拥塞避免、快重传、快恢复 | 无 |
传输速度 | 慢 | 快 |
应用场合 | 对效率要求低,对准确性要求高或要求有连接的场景 | 对效率要求高,对准确性要求低 |
6.TCP 三次握手
-
所谓三次握手(Three-way Handshake),是建立一个TCP连接时,需要客户端和服务器总共发送3个包。
-
三次握手的目的是连接服务器指定端口,建立连接,并同步连接双方的序列号和确认号,交换窗口大小信息。
- 第一次握手(SYN=1, seq=x)
建立连接,客户端发送连接请求报文段,这是报文首部中的同步位SYN=1,同时选择一个初始序列seq=x,此时,客户端进程进入了SYN-SENT(同步已发送状态)。TCP规定,SYN报文段(SYN=1的报文段)不能携带数据,但需要消耗掉一个序号。 - 第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1)
服务器收到客户端的SYN报文段,如果同意连接,则发出确认报文。确认报文中应该ACK=1,SYN=1,确认号ACKnum=x+1;同时,自己还要发送SYN请求信息,SYN=1,为自己初始化一个序列号seq=y,服务器端将上述所有信息放到一个报文段(即SYN+ACK报文段)中,一并发送给客户端,此时,TCP服务器进程进入SYN-RCVD(同步收到)状态。这个报文也不能携带数据,但是同样要消耗一个序号。 - 第三次握手(ACK=1,ACKnum=y+1)
客户单收到服务器的SYN+ACK报文段,再次发送确认包(ACK),SYN标志位0,ACK标志位为1,确认号ACKnum = y+1,这个报文段发送完毕以后,客户端和服务器都进入ESTABLISHED(已建立连接)状态,完成TCP三次握手。
- 第一次握手(SYN=1, seq=x)
7.为什么需要三次握手?两次不行吗?
为了防止已失效的连接请求报文端突然又传到服务端,因而产生错误。
目的:为了防止第一次握手时的请求报文段,在发送到某个地方由于链路拥堵而超时抵达服务器,这时服务器还会响应,向客户端发送确认报文段,而客户端已经超时,所以不会再等下去。而只有客户端及时收到服务器发送的确认报文段,而且及时响应服务器。
具体例子:“如客户端发出连接请求,但因连接请求报文丢失而未收到确认,于是客户端再重传一次连接请求。后来收到了确认,建立了连接。数据传输完毕后,就释放了连接,客户端共发出了两个连接请求报文段,其中第一个丢失,第二个到达了服务端,但是第一个丢失的报文段只是在某些网络结点长时间滞留了,延误到连接释放以后的某个时间才到达服务端,此时服务端误认为客户端又发出一次新的连接请求,于是就向客户端发出确认报文段,同意建立连接,不采用三次握手,只要服务端发出确认,就建立新的连接了,此时客户端忽略服务端发来的确认,也不发送数据,则服务端一致等待客户端发送数据,浪费资源。”
8.四次挥手
TCP连接的拆除需要发送四个包,因此称为四次挥手(Four-way handshake),也叫做改进的三次挥手。客户端或服务器均可主动发起挥手动作。
- 第一次挥手(FIN=1,seq=x)
主机1(可以是客户端,也可以是服务器),设置seq=x,向主机2发送一个FIN报文段,此时主机1进入FIN_WAIT_1状态,这表示主机1没有数据要发送给主机2了。 - 第二次挥手(ACK=1,ACKnum=x+1)
主机2收到主机1发送的FIN报文段,向主机1回一个ACK报文段,ACKnum=x+1,主机1进入FIN_WAIT_2状态,主机2告诉主机1,我“同意”你的关闭请求。 - 第三次挥手(FIN=1,seq=y)
主机2向主机1发送FIN报文段,请求关闭连接,同时主机2进入LAST_ACK状态。 - 第四次挥手(ACK=1,ACKnum=y+1)
主机1收到主机2发送的FIN报文段,向主机2发送ACK报文段,然后主机1进入TIME_WAIT状态,主机2收到主机1的报文段以后,就关闭连接;此时,主机1等待2MSL后依然没有收到回复,则证明Server端已正常关闭,那么,主机1也可以关闭连接了,进入CLOSED状态。
为什么要等待2MSL这个固定时间(两个最大段时间周期,2MSL,2 Maximum Segment Lifetime)之后,没有收到服务器端的ACK,认为服务器端已经正常关闭,遇事自己也关闭连接,进入CLOSED状态。
9.为什么连接的时候是三次握手,关闭的时候却是四次握手?
- 因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文是,很可能并不会立即关闭SOCKET,所以只能先回复ACK报文,告诉Client端,“你发的FIN报文我收到了”,只有等到我Server端所有的报文发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。
- 由于TCP协议是全双工的,也就是说客户端和服务器都可以发起断开连接。两边各发起一次断开连接的申请,加上各自的两次确认,看起来就像执行了四次挥手。
10.Socket套接字传输
根据连接启动的方式以及本地 套接字要连接的目标,套接字之间的连接过程可以分为三个步骤: 服务器监听,客户端请求,连接确认。
(1)服务器监听:是服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态。
(2)客户端请求:是指由客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和 端口号,然后就向服务器端套接字提出连接请求。
(3)连接确认:是指当服务器端套接字监听到或者说接收到客户端套接字的连接请求,它就响应客户端套接字的请求,建立一个新的线程,把 服务器端套接字的描述发给客户端,一旦客户端确认了此描述,连接就建立好了。而服务器端 套接字继续处于 监听状态,继续接收其他客户端套接字的连接请求。
十二、线程与进程
1.什么是进程?
- 正在执行的程序
2.什么是线程?
- 进程内部最小的执行单位
- CPU在一个时间点上只能处理一个线程,但是CPU速度很快,可以交替执行线程
3.什么是多线程?
- 一个进程中可以有多个线程任务
- 多线程的优点:
- 同时并发执行多个任务
- 最大限度地降低CPU的闲置时间,提高CPU的利用率
4.什么时候需要多线程?
- 程序需要同时执行多个任务(任务/线程,都是各自独立的)
5.多线程的优缺点是什么?
- 优点:
- 同时执行多个任务,功能强大
- 提高CPU的利用率,CPU执行是以线程为单位的
- 改善程序结构,将复杂任务分为多个线程,独立运行
- 缺点
- 线程越多,对内存,CPU的占用越高(硬件升级)
- 多个线程对一个共享资源来进行访问,会出现不正常情况
- 解决办法:线程同步,效率低,但是安全
6.进程与线程的区别是什么与联系?
- 线程是进程的子集,一个进程可以有很多线程.
- 一个CPU在同一时刻只能运行一个进程,一个进程在同一时刻只能运行一个线程
- 进程的空间对每个线程而言是共享的
- 一个线程在使用一个进程的时候,其他线程只能等他结束才能使用这一内存
7.创建线程的4种方式是什么?
(1)继承Thread类
- 创建一个类继承Thread类
- 重写Run()方法
- 创建该类的对象
- 调用start()方法
(2)实现Runnable接口
- 创建一个类实现Runnable接口
- 重写Run()方法
- 创造改类的对象
- 将此类作为参数传递给Tread类的构造器中,创建Tread类的对象
- 调用Tread类的start()方法
(3)实现Callable接口
- Callable和Runnable的区别
- Callable的 call() 方法可以返回值和抛出异常,
- 而Runnable的run()方法没有这些功能。
- Callable可以返回装载有计算结果的Future对象。
(4)通过线程池来创建线程
8.线程的优先级
- MAX-PRIORITY:10 最高优先级
- MIN-PRIORITY:1 最低优先级
- NORM-PRIORITY:5 默认优先级
- 牵扯到CPU的执行权
- 时间片:排队先到先执行
- 抢占式:对优先级高的先执行
9.线程的生命周期
新建(NEW):当一个Thread类或者子类的对象被声明或创建时,新生的线程对象处于新建状态
就绪(READY):处于新建状态的线程被Start后,将进入线程队列等待CPU时间片,此时它已具备了运行的条件,只是没分配到CPU资源
运行(RUNNING):当就绪的线程被调度并获得CPU资源时,便进入运行状态,run()方法定义了线程的操作和功能
阻塞(Blocked):在某种特殊情况下,被人为挂起或执行输入输出操作时,让出CPU并临时中止自己的执行,进入阻塞状态
死亡(Terminated):线程完成了它的全部工作或线程被提前强制性地中止或出现异常导致结束
10.java多线程中调用wait() 和 sleep()方法有什么不同?
- Java程序中wait 和 sleep都会造成某种形式的暂停
- wait()方法用于线程间通信,如果等待条件为真且其它线程被唤醒时它会释放锁
- 而 sleep()方法仅仅释放CPU资源或者让当前线程停止执行一段时间,但不会释放锁。
11.守护线程
(1)什么是守护线程
- 守护线程是程序运行的时候在后台提供一种通用服务的线程。
- 当把一个线程设置为守护线程时,守护线程需要等所有的非守护线程全部结束后才会销毁
- java的垃圾回收就是一个典型的守护线程
(2)Java中把线程设置为守护线程的方法是什么?
- 在 start 线程之前调用线程的 setDaemon(true) 方法。
12.线程同步
(1)什么是线程同步?
- 现在有100张火车票,有两个窗口同时抢火车票。
- 多个线程访问同一个共享资源
- 关键字为 : synchronized
- synchronized关键字可以修饰方法,也可以修饰代码块,但不能修饰构造器,抽象方法,成员属性等之前我们学过的StringBuffer,Vector,HashTable等都是线程安全的
(2)如何解决多线程之间线程安全问题?
- 答:使用多线程之间同步synchronized或使用锁(lock)。
(3)为什么使用线程同步或使用锁能解决线程安全问题呢?
- 答:将可能会发生数据冲突问题(线程不安全问题),只能让当前一个线程进行执行。代码执行完成后释放锁,让后才能让其他线程进行执行。这样的话就可以解决线程不安全问题。
(4)什么是多线程之间同步?
- 答:当多个线程共享同一个资源,不会受到其他线程的干扰。
(5)什么地方需要考虑枷锁?
- 答:真正产生共享同一个全局变量的时候。
(6)锁是在什么时候释放的?
- 答:代码执行完毕或者是程序抛出异常,都会把锁释放掉
13.显示锁Lock和隐式锁synchronized
(1)如何使用Lock显示锁?
- 实例化ReentrantLock对象
- 在try块中开启锁
- 在finally块中关闭锁
(2)synchronized和Lock的区别?
- 隐式锁:synchronized
- 多个线程拥有一把锁,谁先获得,谁才可以进入,其他线程等待
- 当持有锁的线程把同步代码中的内容执行完成后,离开同步代码块,会自动释放锁
- 显示锁 Lock
- Lock是显式锁(手动开启和关闭锁);而synchronized是隐式锁,出了作用域自动释放
- Lock只能作用于代码块;而sychronized可以作用于代码块也可以作用于方法
- Lock锁,JVM花费较少时间,性能更好,锁的粒度更小,更有针对性
(3)线程同步机制中优先使用顺序是什么?
- Lock、同步代码块、同步方法;
- 即锁的粒度越小越好。
14.线程死锁
(1)什么是线程死锁?
- 线程死锁是指两个或两个以上的线程互相持有对方所需要的资源,
- 由于synchronized的特性一个线程持有一个资源,或者说获得一个锁,
- 在该线程释放这个锁之前,其它线程是获取不到这个锁的,而且会一直死等下去,因此这便造成了死锁。
(2)死锁产生的条件是什么?
- 互斥条件:一个资源,或者说一个锁只能被一个线程所占用,当一个线程首先获取到这个锁之后,在该线程释放这个锁之前,其它线程均是无法获取到这个锁的。
- 占有且等待:一个线程已经获取到一个锁,再获取另一个锁的过程中,即使获取不到也不会释放已经获得的锁。
- 不可剥夺条件:任何一个线程都无法强制获取别的线程已经占有的锁
- 循环等待条件:线程A拿着线程B的锁,线程B拿着线程A的锁。