JavaSE复习

Java的核心优势:跨平台。

Java的特性和优势:跨平台/可可移植性,安全性,面向对象,简单性,高性能,分布式,多线程,健壮性。

Java程序的运行机制:faa7f1ee81644766bc74c52cf4dcaac2.png

 JVM、JRE、JDK:

JVM:Java虚拟机,不同操作系统有不同的虚拟机,是实现跨平台的核心机制。

JRE:Java运行环境。

JDK:Java开发工具包。

JDK包含JRE,JRE包含JVM。

注释:

给程序员看的。

单行注释://,多行注释:/*  */ ,文档注释:/** */。

标识符:

用来给变量、类、方法以及包进行命名的。

必须以字母(英文或汉字,采用Unicode字符集,汉字和英文字母都是普通字符)、下划线、美元符开头;

其他部分可以是字母、下划线、美元符和数字的任意组合;

大小写敏感且长度无限制;

驼峰命名;

不可以是关键字。

变量:

局部变量:定义在方法或语句块内,使用之前赋初值。

成员变量(实例变量):类内部,方法外部,不初始化会赋默认值:int 0,double 0.0,char '\u0000',boolean false。

静态变量(类变量):类内部,static修饰,不初始化会赋默认值。

常量:

用final修饰,只能初始化一次,不能修改。

基本数据类型:

1字节8位

数值型:byte(1字节),short(2字节),int(4字节),long(8字节),float(4字节,精确到7位),double(8字节)

b0cbbf33523a4d03b306f015061c4eea.png

 默认整型为int,声明long需要在后面加l或L。

0开头8进制,0x/X开头16进制,0b/B开头2进制。

0c4ac960913c4305831b82f9e1fa4de6.png

默认浮点为double,声明float需要在后面加f或F,浮点数不精确有误差,尽量不要直接比较,可能会出问题,精确计算需要使用BigDecimal类。

字符型:char(2字节)

Unicode字符,可允许有65536个字符。

布尔型:boolean

一般是4个字节,定义在数组中是1个字节。

引用数据类型4个字节。

运算符:

二元运算符(+-*/%):

整数运算:两个操作数有一个为long,则结果为long,否则结果都为int。

浮点运算:两个操作数有一个为double,则结果为double,否则结果为float。

一元运算符(++ --):

i++先使用i再自增;

++i先自增再使用i。

扩展赋值运算符:

a+=b+3 (a=a+(b+3))

逻辑运算符:

71788278c73546de8a35c29742c36f90.png


移位运算:左移相当于乘2,右移相当于除以2。

算数符优先级:逻辑非>逻辑与>逻辑或

自动类型转换:

可能会有精度损失。

9f6dae4beeeb4fe1aa3bae7b9b510c83.png

switch语句中case标签在JDK1.5之前必须是整数(long类型除外)或者枚举,不能是字符串,在JDK1.7之后允许使用字符串(String)。

do-while至少执行一次,while可能一次都不执行。

无限循环while(true),for(;;)。

break结束循环,continue结束本次循环,开始下一次循环。

方法声明:形参(在方法声明时用于接收外界传入的数据)。

方法调用:实参(调用方法时实例传给方法的数据)。

方法重载:实际是完全不同的方法,只是名字相同。发生在一个类中方法名相同,形参列表不同,与返回值类型和访问修饰符无关,可以抛出不同的异常。

面向过程是以过程为中心的编程思想,“执行者思维”,注重流程化,按照特定顺序一步一步实现功能。而面向对象是以对象为中心的编程思想,“设计者思维”,先把要完成的功能封装成一个一个的对象,通过调用对象的方法或属性来实现功能。 面向对象具有高度的拓展性和复用性,特点是继承、封装、多态;而面向过程的优点在于流程化使得编程任务清晰明了。

成员变量默认值:

ad9d11f0eacb46a983fc6aff81c2a5a7.png

对象实例化存的是地址。

构造方法:

通过new调用,

没有返回值,

没有定义的话会默认有一个无参构造方法,

名与类名一致。

虚拟机栈(简称:栈)的特点如下:

1.栈描述的是方法执行的内存模型。每个方法被调用都会创建一个栈帧(存储局部变 量、操作数、方法出口等)

2.JVM为每个线程创建一个栈,用于存放该线程执行方法的信息(实际参数、局部变 量等)

3.栈属于线程私有,不能实现线程间的共享

4.栈的存储特性是“先进后出,后进先出”

5.栈是由系统自动分配,速度快,栈是一个连续的内存空间。

堆的特点如下:

1.堆用于存储创建好的对象和数组(数组也是对象)

2. JVM只有一个堆,被所有线程共享

3.堆是一个不连续的内存空间,分配灵活,速度慢。

方法区(又叫静态区,也是埔特点如下:
1.方法区是JAVA虚拟机规范,可以有不同的实现。
i.JD7以前是“永久代”

ii. JDK7部分去除“永久代”,静态变量、字符串常量池都挪到了堆内存中

iii. JDK8是“元数据空间”和堆结合起来。

2. JVM只有一个方法区,被所有线程共享!

3.方法区实际也是堆,只是用于存储类、常量相关的信息

4.用来存放程序中永远是不变或唯一的内容。(类信息、静态变量、字符串常量等)

垃圾回收GC:

堆中对象的管理。自动回收没有引用的对象,直接赋值为null。

1.引用计数法

堆中的每个对象都对应一个引用计数器,当有引用指向这个对象时,引用计数器加1,而当指向该对象的引用失效时(引拥变为nul),引用计数器减1,最后如果该对象的引用计算器的值为0时,则Java垃圾回收器会认为该对象是无用对象并对其进行回收。优点是算法简单,缺点是“循环引用的无用对象”(两个对象内部属性互相指向)无法别识别。

2.引用可达法(根搜索算法)
程序把所有的引用关系看作一张图,从一个节点GC ROOT 开始,寻找对应的引用节点,找到这个节点以后,继续寻找这个节点的引用节点,当所有的引用节点寻找完毕之后,剩余的节点则被认为是没有被引用到的节点,即无用的节点。

堆内存划分为3种:年轻代,年老代,持久代。JVM将堆内存划分为Eden、Survivor和Tenured/Old 空间。

1.年轻代

所有新生成的对象首先都是放在Eden区,年轻代的目标就是承可能快速的收集掉那些生命周期短的对象,对应的是Minor GC,每次Minor GC会清理年轻代的内存,算法采用效率较高的复制算法,频紧的操作,但是会浪费内存空间。新来的对象放在Eden中,当Eden满了后放在Surviver1中,当Surviver1满了后放在Surviver2中,当Surviver2满了后放在Surviver1中,如此反复,当一个对象被操作15次后,会被放到年老代区。当“年轻代”区域存放满对象后,就将对象存放到年老代区域。

2.年老代

 在年轻代中经历了N(默认15)次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。年老代对象越来越多,我们就需要启动Major GC和Full GC(全量回收),来一次大扫除,全面清理年轻代区域和年老代区域。

3.永久代

用于存放静态文件,如Java类、方法等。持久代对垃圾回收没有显著影响。JDK7以前就是“方法区”的一种实现。JDK8以后已经没有“永久代”了,使用metaspace元数据空间和堆替代。

Minor GC:用于清理年轻代区域。Eden区满了就会触发一次Minor GC。清理无用对象,将有用对象复制到“Survivor1" .“Survivor2”区中。

Major GC:用于清理老年代区域。

Full GC:用于清理年轻代、年老代区域。成本较高,会对系统性能产生影响。

finalize:用来释放对象或资源的方法。

System.gc():通知JVM,建议启动Full GC。

内存泄露场景:(用完了不释放)

创建大量无用的对象,静态集合类的使用,各种连接对象(IO流对象、数据库连接对象、网路连接对象)未关闭,监听器的使用。

创建一个对象分为如下四步:
1.分配对象空间,并将对象成员变量初始化为0或空
2.执行属性值的显式初始化
3.执行构造方法
4.返回对象的地址给相关的变量
this的本质就是“创建好的对象的地址”,this不能用于static方法中。

静态方法中不能调用非静态方法和属性。

方法重写:发生在继承关系中,方法名、形参列表相同,返回值和声明异常类型子类小于等于父类,访问权限子类大于等于父类。


final:

修饰变量:基本数据类型不可更改,引用数据类型只能指向初始化时的对象,

修饰方法:不能被子类重写,但可以被重载,

修饰类:不能被继承。

三大特性:

封装:将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问成员变量private,提供对应的get/set方法,boolean类型的get方法是is开头。好处:通过方法来控制成员变量的操作,提高了代码的安全性把代码用方法进行封装,提高了代码的复用性。

36affd1d1b8b4b3a8ee3101161475577.png

protected:

1.若父类和子类在同一个包中,子类可访问父类的protected成员,也可访问父类对象的protected成员。

2.若子类和父类不在同一个包中,子类可访问父类的protected成员,不能访问父类对象的protected成员。

继承:可以使得子类具有父类的属性和方法,还可以在子类中重新定义,以及追加属性和方法,继承带来的好处:提高了代码的复用性(多个类相同的成员可以放到同一个类中),提高了代码的维护性(如果方法的代码需要修改,修改一处即可),继承弊端:继承让类与类之间产生了关系,类的耦合性增强了,当父类发生变化时子类实现也不得不跟着变化,削弱了子类的独立性,继承的应用场景:使用继承,需要考虑类与类之间是否存在is a的关系,不能盲目使用继承。

子类必须实现父类的抽象方法。

多态:多态指的是同一个方法调用,由于对象不同可能会有不同的行为。多态是方法的多态,不是属性的多态。多态存在的3个必要条件:继承,方法重写,父类引用指向子类对象。父类引用指向子类对象后,用该父类引用调用子类重写的方法,此时多态就出现了。可以让程序更灵活,没有多态需要写大量方法的重载。

向上转型:自动转型,编译的时候编译类型为父类,只能使用父类有的方法。

向下转型:强转,可以使用子类独有的方法。

Animal a = new Dog();

Dog d = (Dog) a;

Cat c = (Cat) a;  //会报错,类型转换错误

==和equals:

==是运算符;如果比较的对象是基本数据类型,则比较的是其存储的值是否相等;如果比较的是引用数据类型,则比较的是所指向对象的地址值是否相等(是否是同一个对象)。

equals 方法不能用于比较基本数据类型,如果没有对 equals 方法进行重写,则相当于“==”,比较的是引用类型的变量所指向的对象的地址值,重写之后比较的是对象的值。

return:返回值,结束方法运行。

如果构造方法第一行没有写super()或this(),默认加一个super()。

抽象类:

1.有抽象方法的类只能定义成抽象类 。

2.抽象类不能实例化,即不能用new来实例化抽象类。

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

4.抽象类只能用来被继承。

5.抽象方法必须被子类实现。

接口:

1.访问修饰符:只能是public或默认。

2.接口名:和类名采用相同命名机制。

3.接口可以多实现。

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

5.方法:接口中的方法只能是public abstract。可以省略。

2693e81a713b4ae5a81097ddcd81cee0.png

 JAVA8 (含8)之后,以后允许在接口里定义默认方法和静态方法。

1.默认方法

Java8及以上版本,允许给接口添加一个非抽象的方法实现,只需要使用default 关键字即可,这个特征又叫做默认方法(也称为扩展方法)。 默认方法和抽象方法的区别是抽象方法必须要被实现,默认方法不是。作为替代方式,接口可以提供默认方法的实现,所有这个接口的实现类都会通过继承得到这个方法。

2静态方法
JAVA8以后,我们也可以在接口中直接定义静态方法的实现。这个静态方法直接从属于接口(接口也是类,一种特殊的类),可以通过接口名调用。如果子类中定义了相同名字的静态方法,那就是完全不同的方法了,直接从属于子类。可以通过子类名直接调用。

String:不可变字符序列,Unicode字符序列。

String str1 = new String("java");

栈区创建str1指向堆区的数组,数组指向方法区中的常量池,str1是数组的地址。

String str2 = "java";

栈区创建str2直接指向方法区中的常量池,str2是常量池的地址。

f5c349da153f4eb099e7e5620fe55cb3.png

当外部类和内部类成员变量重名时,可以用外部类.this.变量名调用外部类变量。

内部类的作用:
内部类提供了更好的封装。只能让外部类直接访问,不允许同一个包中的其他类直接访问。
内部类可以直接访问外部类的私有属性,内部类被当成其外部类的成员。但外部类不能访问内部类的内部属性。

非静态内部类(外部类里使用非静态内部类和平时使用其他类没什么不同)
1.非静态内部类对象必须寄存在一个外部类对象里。因此,如果有一个非静态内部类
对象那么一定存在对应的外部类对象。非静态内部类对象单独属于外部类的某个对象。
2.非静态内部类可以直接访问外部类的成员,但是外部类不能直接访问非静态内部类成员。
3.非静态内部类不能有静态方法、静态属性和静态初始化块。

4.成员变量访问要点:
1.内部类里方法的局部变量∶变量名。2.内部类属性:this.变量名。3.外部类属性:外部类名.this.变量名。

静态内部类:1.静态内部类可以访问外部类的静态成员,不访问外部类的普通成员。2.静态内部类看做外部类的一个静态成员。

匿名内部类

局部内部类:作用域仅在方法中。

数组:

特点1.长度是确定的,一旦被创建,大小不可改变。 2.元素类型必须是相同类型。  3.数组类型可以是基本类型和引用类型。  4.数组变量属于引用类型,数组也是对象,数组中的元素相当于对象的属性,在堆中存储。数组只有在实例化后才会被JVM分配内存。

静态初始化:int[] a={2,3};

动态初始化:a[0]=0;

数组遍历方式:1.普通for  2.增强for循环for-each(一般用于读取值)

数组拷贝方式:System.arraycopy(原数组,原数组开始拷贝的位置索引,目标数组,目标数组接收数据的索引,个数)

java.util.Arrays:

Arrays.toString  返回数组内容

Arrays.sort  对数组排序升序

Arrays.binarySearch(数组,数据) 在属于中查找数据,有返回索引,没有返回负数

Arrays.fill(a,2,4,100)  将[2,4)索引的元素替换为100

二维数组:5c2bea1556d54ef6a75c10381e675336.png

Comparable接口:定义比较规则,重写compareTo方法,参数为要比较的对象。


JDK1.5以后引入自动装箱/拆箱。

自动装箱:Integer i = 1;JVM执行了Integer.valueOf(1)

自动拆箱:JVM执行了intValue()

空指针异常:对象为空,调用了对象的属性和方法

包装类的缓存问题:

当数字在[-128,127]之间时,返回缓存数组中的元素。

Integer i1 = 500;          Integer i2 = 500;

Integer i3 = 100;          Integer i4 = 100;

System.out.println(i1==i2);   //false

System.out.println(i3==i4);   //true

String,StringBuffer,StringBuilder(都由final修饰):

String:不可变字符序列,字符串内容存在一个数组中,由final修饰所以不可变

 

//编译器做了优化直接在编译的时候将字符串进行拼接

String str1 = "hello" + " java";//相当于str1 = "hello java";

String str2 = "hello java";

System.outprintln(str1 == str2);//true

String str3 = "hello";

String str4 = " java";

//编译的时候不知道变量中存储的是什么,所以没办法在编译的时候优化

String str5 = str3 + str4;

System.out.printIn(str2 == str5);//false

 

StringBuffer:线程安全,效率低,同步方法

StringBuilder:线程不安全,效率高,建议使用

重载的public StringBuilder append(...)

方法可以为该StringBuilder对象添加字符序列,仍然返回自身对象。

方法 public StringBuilder delete(int start,int end)

可以删除从start开始到 end-1为止的一段字符序列,仍然返回自身对象。

方法 public StringBuilder deleteCharAt(int index)

移除此序列指定位置上的char,仍然返回自身对象。

重载的 public StringBuilder insert(...)

方法可以为该StringBuilder 对象在指定位置插入字符序列,仍然返回自身对象。

方法 public StringBuilder reverse()

用于将字符序列逆序,仍然返回自身对象。

方法 public String toString()

返回此序列中数据的字符串表示形式。

和String类含义类似的方法:

public int indexOf(String str)

public int indexOf(String str,int fromIndex)

public String substring(int start)

public String substring(int start,.int end)

public int length()

char charAt(int index)

 

System.currentTimeMillis();系统当前时间距离1970-1-1 0:0:0的毫秒数

DateFormat(抽象类)和SimpleDateFormat:时间和字符串相互转换  yyyy-MM-dd hh:mm:ss

format()Date时间转字符串  parse()字符串转时间

Calendar抽象类和GregorianCalendar日期计算,月份0-11,周日是1

枚举enum:定义一组常量

enum 枚举名{

              枚举体(常量列表)

}

异常:

所有异常对象都是派生于Throwable类的一个实例,又派生了两个子类Error:非代码异常,Exception:代码异常,分位编译时异常和运行时异常。

异常的处理:

1.捕获异常try-catch-finally

2.声明异常throws抛出

(1)throw 在方法体内使用,throws 在方法声明上使用;

(2)throw 后面接的是异常对象,只能接一个。throws 后面接的是异常类型,可以接多个,多个异常类型用逗号隔开;

(3)throw 是在方法中出现不正确情况时,手动来抛出异常,结束方法的,执行了 throw 语句一定会出现异常。而 throws 是用来声明当前方法有可能会出现某种异常的,如果出现了相应的异常,将由调用者来处理,声明了异常不一定会出现异常。

3.JDK7后新特性try-with-resource自动关流,将finally简化,实现AutoClosable接口

try(流;){

操作

}catch(异常){}

自定义异常

/**IllegalAgeException:非法年龄异常,继承Exception类*/
class IllegalAgeException extends Exception {
    //默认构造器
    public IllegalAgeException() {

    }
    //带有详细信息的构造器,信息存储在message中
    public IllegalAgeException(String message) {
        super(message);
    }
}

容器:

Java的容器主要分为2个大类,即Collection和Map。Collection代表着集合,而Map则是映射,保留键值对两个值。

Collection包括List和Set。

List: 存储的元素是有序的、可重复的。

Set :存储的元素是无序的、不可重复的。

Map (用 key 来搜索的专家) :使用键值对存储,key 是无序的、不可重复的,value 是无序的、可重复的,每个键最多映射到一个值。

f4bed33e919b411387684ab684072dec.png

56e255eee6614f5db80474eb15e3aca6.png

TreeSet自定义排序规则让元素所属的类实现Comparable接口,重写compareTo()方法

bdfda2ced7d94a7da77338a89eb647fa.png 

ArrayList的底层工作原理

1.在构造ArrayList时,如果没有指定容量,那么内部会构造一个空数组,如果指定了容量,那么就构造出对应容量大小的数组

2.在添加元素时,会先判断数组容量是否足够,如果不够则会扩容,扩容按1.5倍扩容,容量足够后,再把元素添加到数组中

3.在添加元素时,如果指定了下标,先检查下标是否越界,然后再确认数组容量是否足够,不够则扩容,然后再把新元素添加到揩指定位置,如果该位置后面有元素则 后移

4.再获取指定下标的元素时。先检查下标是否越界,然后从数组中取出对应位置的元幸

ArrayList和LinkedList区别

1.首先,他们的底层数据结构不同,ArrayList底层是基于数组实现的,LinkedList底层是基于链表实现的

2.由于底层数据结构不同,他们所适用的场景也不同,ArrayList更适合随机查找,LinkedList更适合删除和添加,查询、添加、删除的时间复杂度不同

3.另外ArrayList和LinkedList都实现了List接口,但是LinkedList还额外实现了Deque接口,所以LinkedList还可以当做队列来使用

线程是操作系统能够运行运算调度的最小单位。它包含在进程之中,是进程中的实际运作单位。(简单理解:应用软件中相互独立,可以同时运行的功能)
进程是程序的基本执行实体。
可以通过多线程让程序同时做多件事情。
多线程作用:提高效率。
多线程的应用场景:想让多个事情同时运行就需要多线程,拷贝、迁移大文件,加载大量的资源文件,聊天软件,后台服务器。
并发:在同一时刻,有多个指令在单个CPU上交替执行。
并行:在同一时刻,有多个指令在多个CPU上同时执行。
并发和并行可能同时进行。
创建线程的3种方式:
1.继承Thread类
1)创建一个类,继承 Thread并重写 run 方法
2)创建该类对象 执行 start 方法
2.实现Runnable接口
1)创建一个类 实现Runnable接口并重写 run 方法
2)创建一个 该类 对象
3)创建一个 Thread 对象,构造方法入参为 该类 对象
4)Thread 对象 执行start方法
3.实现Callable和Future接口(可以获取到多线程运行的结果)
1)创建一个类实现 Callable 接口 ,重写 call 方法(返回值是多线程运行的结果,泛型是返回值类型)
2) 创建该类的对象(表示多线程要执行的任务)
3) 创建FutureTask对象ft(表示线程,参数为该类对象)
4)创建Thread对象(参数为ft),启动,ft.get为线程结果
小结:
继承Thread类
子类继承Thread类
启动线程:子类对象.start()
**不建议使用:**避免OOP单继承局限性,可扩展性差
实现Runnable接口
实现runnable接口具有多线程能力
启动线程:传入目标对象+Thread对象.start()
**推荐使用:**避免单继承局限性,灵活方便但编程相对复杂,方便同一个对象被多个线程使用
String getName()   返回此线程的名称
void setNane(String name) 设置线程的名字(构造方法也可以设置名字) 线程默认名字Thread-x(0,1..)
static Thread currentThread() 获取当前线程的对象 当JVM启动以后,会自动启动多条线程,main线程会调用main方法,并执行里面的代码
static void sleep(long time) 让线程休眠指定的时间,单位为毫秒
setPriority(int newPriority) 设置线程优先级 1-10 默认为5 数值越大抢占到CPU的概率越大 不在范围内会抛出异常
inal (int getPriority) 获取线程优先级
final void setDaemon(boolean on) 设置为守护线程 其他非守护线程执行完毕后,守护线程会陆续结束 例如:QQ聊天和发送文件 当关闭聊天后,文件也就没有发送的必要,所以发送文件可以设置为守护线程
public static void yield() 出让/礼让线程 出让当前CPU的执行权 
public final void join() 插入/插队线程 把线程插入到当前线程之前 线程执行完毕后当前线程才会执行

线程生命周期

7c6ea88e778841cca2ab300a8ca327a3.png

 线程安全出现的条件:

多线程环境;有共享数据;多条数据操作共享数据

线程安全问题解决方案:

1.同步代码块synchronized(锁对象){操作共享数据的代码}

锁对象,一定要是唯一的,用static修饰,否则就相当于多个锁,没有意义,一般使用当前类.class,字节码文件对象一定是唯一的

好处:解决了多线程的数据安全问题

坏处:线程很多每个线程都会去判断同步上的锁,浪费资源,降低程序运行效率

2.同步方法:修饰符 synchronized 返回值类型 方法名(方法参数){}    同步方法是锁住方法里的代码,锁对象不能自己指定(非静态:this   静态:当前类的字节码文件对象)

Lock:

虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁, 为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock

Lock实现提供比使用synchronized方法和语句可以获得更广泛的锁定操作Lock中提供了获得锁和释放锁的方法

void lock():获得锁 写在try上面

void unlock():释放锁   需要放在finally

Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来实例化ReentrantLock的构造方法

ReentrantLock():创建一个ReentrantLock的实例

如果用继承Thread的方法 lock需要用static修饰,因为需要创建多个对象

死锁:

由于多个线程相互持有对方所需要的资源,导致这些线程处于等待状态,无法继续执行。

不要让两个锁嵌套。

生产者消费者(等待唤醒机制):

280d80c56eb141ed9807f48e763f8f6d.png

void wait() 线程等待,直到被唤醒  锁对象.wait  让当前线程跟锁绑定 否则会唤醒其他线程

void notify() 随机唤醒单个线程

void notifyAll() 唤醒所有线程  锁对象.notifyAll  唤醒绑定在这把锁上的所有线程

生产者:1.判断桌子上是否有食物

2.有:等待

3.没有:制作食物

4.把食物放在桌子上

5.叫醒等待的消费者开吃

消费者:1.判断桌子上是否有食物

2.如果没有就等待

3.如果有就开吃

4.吃完之后,唤醒生产者继续做

run方法,1.循环  2.同步代码块  3.判断共享数据是否到了末尾(到了末尾)  4.判断共享数据是否到了末尾(没到末尾)

阻塞队列实现等待唤醒机制:

put() 将参数放入队列,放不进去会阻塞

take() 取出第一个数据,取不到会阻塞

不用锁 两个方法底层有锁

线程状态:

 11a14d701a5d43cf8eb3485e0d77ed59.png

 2375af2f68924df3b7a6f220ebe5253c.png

虚拟机没有运行状态是因为当线程抢到CPU执行权的时候会把当前线程交给操作系统去管理。

线程池:

主要核心原理:1.创建一个池子,池子中是空的   2.提交任务时,池子会创建新的线程对象,任务执行完毕,线程归还给池子,下回再次提交任务时,不需要创建新的线程,直接复用已有的线程   3.如果体检任务时,池子中没有空闲线程,也无法创建新的线程,任务就会排队等待

Executors:线程池的工具类通过调用方法返回不同的线程池对象

86e152f0303f43d6a02e129fa010d2a2.png

并不是真正没有上限,上限为int最大值 21亿

线程池7个参数:

1.核心线程数量:不能小于0

2.线程池中最大线程的数量:不能小于等于0,大于等于核心线程数量

3.空闲线程最大的存活时间(值):不能小于0

4.最大存活时间(单位):用TimeUnit指定

5.任务队列:不能为null new ArrayBlockingQueue(指定长度)  Link(不指定长度)

6.创建线程工厂:不能为null  Executors.defaultThreadFactory()

7.任务拒绝策略:不能为null

临时线程:核心线程都在忙,阻塞队列已经排满,才会创建临时线程。

任务执行时不一定按照提交顺序,任务可能在阻塞队列中,但后面的任务会被临时线程服务。

任务个数>核心线程+临时线程+队列长度 就会触发拒绝策略

f4ca681074dc439e80037fec34ec7045.png

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值