- 1. 请你谈谈Java中是如何支持正则表达式的操作的?
- 2. 请你简单的描述一下正则表达式及其用途。
- 3.请你比较一下Java和JavaScript
- 4.请你说明一下,在Java中是如何跳出当前的多重嵌套循环的
- 5.请你讲讲&和&&的区别?
- 6.int 和 integer有什么区别?
- 7.请你说说string、stringbuilder和stringbuffer的区别?
- 8.请说明String是基本数据类型吗?
- 9.请你讲讲数组Array和集合ArrayList的区别?什么时候使用Array而不是ArrayList?
- 10.List接口下的实现类有哪些?它们之间的特点?
- 11.Set接口下的实现类有哪些?它们之间的特点?
- 12.请你解释什么是值传递和引用传递?
- 13.请你解释为什么会出现4.0-3.6=0.40000001这种现象?
- 14.请你讲讲一个十进制的数在内存中是怎么存的?
- 15.你知道Java8的新特性吗?请简单介绍下。
- 16.请你说说lambda表达式的优点及缺点。
- 17.请你解释Object若不重写hashCode()的话,hashCode()是如何计算出来的?
- 18.请你解释下为什么重写equals方法还要重写hashCode方法?
- 19.请你介绍下map的分类和常见的情况
- 20.HashMap的实现原理
- 21.说一说map集合有几种遍历方式?
- 22.请你讲讲Java里面的final关键字是怎么用的?
- 23.请你谈谈关于synchronized和lock。
- 24.请介绍一下volatile关键字?
- 25.请介绍下synchronized锁,如果用这个关键字修饰一个静态方法,锁住了什么?如果修饰成员方法,锁住了什么?
- 26.请解释Java中的概念,什么是构造函数?什么是构造函数重载?什么是复制构造函数 ?
- 27.请你谈谈面向对象的“六原则一法则”
- 28.请说明如何通过反射获取和设置对象私有字段的值?
- 29.请说明内部类可以引用它包含类的成员吗?如果可以,有没有限制的
- 30.请说明Java语言 如何进行异常处理的?关键字throws、throw、try、catch、finally分别代表什么意义?在try块中可以抛出异常吗?
- 31.请判断当一个对象被当作参数传递给一个方法后,此方法可以改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递,还是引用传递?
- 32.请你谈谈如何通过反射创建对象?
- 33.请说明Comparable和Comparator接口的作用以及它们的区别。
- 34.请说明final、finally、finalize的区别。
- 35.请解释下extends和super泛型限定符。
- 36.讲讲什么是泛型?
- 37.ArrayList的扩容机制
- 38.ConcurrentHashMap 和 HashTable 的区别
- 39.如何保证线程的安全性?
- 40.并发和多线程的关系和区别?
- 41.请你简要说下线程的基本状态以及状态之间的关系?
- 42.线程和进程的区别
- 43.创建线程的方式有哪些?
- 44.run()方法和start()方法的区别;
- 45.sleep()方法和wait()方法的区别;
- 46.常见的线程池有哪些?
- 47.使用线程池的优点
- 48.自定义线程池ThreadPoolExecutor的构造方法中的七个参数有哪些?
- 49.
1. 请你谈谈Java中是如何支持正则表达式的操作的?
- Java中的String类提供了支持正则表达式操作的方式,包括:matches()、replaceFirst()、replaceAll()、split()。此外Java中可以使用Pattern类表示正则表达式对象,它提供了丰富的API进行各种正则表达式的操作。
2. 请你简单的描述一下正则表达式及其用途。
- 在编写处理字符串的程序时,经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。换句话说正则表达式就是记录文本规则的代码。
3.请你比较一下Java和JavaScript
- JavaScript与Java是两个公司开发的两个不同的产品。Java是sun公司推出的面向对象的程序设计语言,特别适合互联网应用程序的开发。而Javascript是Netscape公司的产品,为了扩展Netscape浏览器的功能而开发的一种可以嵌入web页面中运行的基于对象与事件驱动的解释性脚本语言,它可以用来制作与网络无关的,与用户交互作用的复杂软件。
- Java的源代码在执行前,必须经过编译;Javascript是一种解释性编程语言,其源代码不需要经过编译,由浏览器解释执行。
- Java采用的是强类型变量检查,即所有变量在编译之前必须声明;Javascript中的变量是弱类型的,甚至在使用变量前可以不作声明,Javascript的解释器在运行时检查推断其数据类型。
4.请你说明一下,在Java中是如何跳出当前的多重嵌套循环的
- 在最外层循环前加一个标记如A,在使用break A 可以跳出多重循环。
5.请你讲讲&和&&的区别?
- 首先&运算有两种用法:①按位与;②逻辑与。&&运算符是短路运算,即当左边的表达式为false,右边的表达式就不会进行运算直接短路掉,而&运算,则还会进行右边的运算。因此在运算的效率上&&效率要快些。
6.int 和 integer有什么区别?
- Java是一个近乎纯净的面向对象编程语言,但是为了编程的方便还是引入了基本数据类型,但是为了能够将这些基本数据类型当成对象操作,Java为每个基本数据类型都引入了相对应的包装类。int的包装类就是integer,从Java5开始引入了自动拆箱和自动装箱机制,使得二者可以互相转换。
7.请你说说string、stringbuilder和stringbuffer的区别?
- string:用string类创建的字符串是不可变的,因为string类是final修饰的类,所以它不可以被被继承和改写,存储字符的value属性也是被final修饰的,因而初始化后被不能发生改变,也没有提供相关的set方法,即使发生了变化那也已经生成了新的对象,因而它也是线程安全的。
- Stringbuilder:用它创建的字符串是可变的,每次改变字符串,返回的对象都是同一个对象,没有对方法加同步锁,线程不安全,效率相对而言比较快。
- StringBuffer:用它创建的字符串也是可变的,每次改变字符串,返回的对象都是同一个对象,底层对方法加了同步锁,线程安全,效率相对而言较慢。
8.请说明String是基本数据类型吗?
- 不是;基本数据类型包括byte、short、char、int、long、float、double和boolean。
- 而string是被final修饰的类。
9.请你讲讲数组Array和集合ArrayList的区别?什么时候使用Array而不是ArrayList?
- 它们两者之间的不同点:Array可以包含基本数据类型和引用数据类型的元素,而ArrayList只能包含引用数据类型的元素。
- Array的大小是固定的,而ArrayList是有扩容机制的。
- ArrayList提供了更多的方法和特性,比如:addAll()、removeAll()、iterator()等等。
- 对于基本类型数据,集合使用自动装箱来减少编码的工作量,但是,当处理固定大小的基本数据类型的时候,这种方式相对比较慢,因此会使用数组效率更好。
10.List接口下的实现类有哪些?它们之间的特点?
- ArrayList
- 优点: 底层数据结构是数组,因为数组基于索引查询,相对于linkedList查询快,效率高,可重复,有序性,但是因为底层是数组的原因,增删元素都必须要牵动整个数组中的元素,因而它对元素的增删效率比较低的;缺点: 线程不安全,。
- LinkedList
- 优点: 底层数据结构是链表,当将元素存到相对应的位置或者从相对应的位置删除时只需让前面的元素和当前元素相互记录地址值或将地址值相互断开,再让当前元素与下一个元素相互记录地址值或将地址值相互断开,这样就相对的效率高些,可重复性,有序性。缺点: 线程不安全,查询慢,
- Vector
- 优点: 底层数据结构是数组,查询快,增删慢。缺点: 线程安全,效率低
11.Set接口下的实现类有哪些?它们之间的特点?
- HashSet底层数据结构是哈希表。(无序,唯一)如何来保证元素唯一性?1.依赖两个方法:hashCode()和equals()
- LinkedHashSet底层数据结构是链表和哈希表。(FIFO插入有序,唯一)
- 1.由链表保证元素有序
- 2.由哈希表保证元素唯一
- TreeSet底层数据结构是红黑树。(唯一,有序)
- 如何保证元素排序的呢?自然排序比较器排序
- 2.如何保证元素唯一性的呢?根据比较的返回值是否是0来决定
12.请你解释什么是值传递和引用传递?
- 值传递就是对于基本数据类型的变量而言的,传递的是该变量的一个副本,改变副本不影响源变量;引用传递一般是对于引用数据类型的变量而言的,传递的是该对象地址值的一个副本,并不是源对象本身,所以对引用对象进行操作会同时改变源对象。
13.请你解释为什么会出现4.0-3.6=0.40000001这种现象?
- 因为计算机底层是以二进制的方式对数据进行处理运算的,而二进制的小数无法精确的表达十进制的小数,在进行十进制的小数运算时要先将十进制转换成二进制进行运算,这个过程会出现误差。
14.请你讲讲一个十进制的数在内存中是怎么存的?
1.以补码的形式进行存储。
15.你知道Java8的新特性吗?请简单介绍下。
1.Java8新增了lambda表达式、方法引用、默认方法即接口中默认的方法实例、新的编译工具如:Nashorn引擎jjs、类依赖分析器jdeps,StreamAPI,增强了Date Time API的功能、Optional类等。
16.请你说说lambda表达式的优点及缺点。
- 优点有:代码简洁;非常容易并行计算;可能代表未来的编程趋势;
- 缺点有:若不用并行计算,很多时候计算速度没有传统的for循环块;不容易调试;易读性较差。
17.请你解释Object若不重写hashCode()的话,hashCode()是如何计算出来的?
- Object的hashcode方法是本地方法,也就是c语言或c++实现的,该方法直接返回对象的内存地址
18.请你解释下为什么重写equals方法还要重写hashCode方法?
- 在HashMap中,如果要比较key是否相等,要同时使用这两个方法,因为类中HashCode方法继承于Object类,其hashCode码默认的是对象的内存地址,这样即便有相同含义的两个对象,从某种角度比较也是不相等的。因而还要重写equals方法进行对对象的内容进行比较。
19.请你介绍下map的分类和常见的情况
- Java为数据结构中的映射定义了一个Map接口,它有四个实现类,分别是HashMap、Hashtable、LinkedHashMap、TreeMap
- map主要用于存储键值对的双列集合,根据键获取值,因此不允许键重复,如果重复了就把值覆盖了,但允许值的重复。
- HashMap是一个常用的Map,它根据键的哈希值存储数据,根据键可以直接获取它的值,具有很快的访问速度,遍历时,取得数据的顺序是无序的,HashMap允许null值,HashMap线程不安全,任意时刻可以有多个线程同时访问HashMap,可能会导致数据不一致。如果需要同步,可以使用Collections的synchronizedMap()方法使HashMap具有同步的能力,或者使用线程更安全的ConcurrentHashMap。
- Hashtable与HashMap类似,他继承Dictionary类,不同的是,他不允许记录的键或值为null;它线程安全,任意时刻只能允许一个线程访问Hashtable,因此Hashtable的效率相对而言比较慢
- TreeMap实现了SortMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以用指定排序的比较器进行排序,当时Iterator(迭代器)遍历时,得到的记录是有序的。
- LinkedHashMap可以实现输入顺序与输出顺序保持一致。
20.HashMap的实现原理
- HashMap底层是数组和链表也就是链表散列,添加元素时HashMap 通过key 的hashCode方法,经过相应的处理过后得到 hash 值,然后通过数组长度经过哈希判断当前元素存放的位置,如果当前位置存在元素的话,就判断该元素与要存入的元素的 hash 值以及 key 是否相同,如果相同的话,直接覆盖,不相同就通过拉链法解决冲突;JDK1.8之后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)及数组长度达到64时,将链表转化为红黑树,以减少搜索时间;当链表长度短于6的时候会转化为链表;
- 扩容机制:HashMap默认长度16、达到75%的阀值会自动按其两倍的长度扩容;扩充后数据的位置变化:jdk1.8中在计算新位置的时候并没有跟1.7中一样重新进行hash运算,而是用了原位置+原数组长度这样一种很巧妙的方式,而这个结果与hash运算得到的结果是一致的,只是会更块。至于为什么新位置要么是原位置,要么是原位置+原数组长度的位置是由于每次扩容相当于数组长度的高位多了一个1,新的hash运算取决于hashCode在这一位上的值是0还是1,如果是0则无需变化位置,如果是1则位置为原位置+原数组长度的位置。1.8之后的尾插法和1.7的头插法有什么区别:JDK1.7是用单链表进行的纵向延伸,当采用头插法时会容易出现逆序且环形链表死循环问题。但是在JDK1.8之后是因为加入了红黑树使用尾插法,能够避免出现逆序且链表死循环的问题。
21.说一说map集合有几种遍历方式?
- 方式一:调用map的keySet方法,返回Map集合中所有的键并封装到set集合中,然后可以用增强for进行调用get方法获取值;
- 方法二:调用map集合的entrySet方法,获取所有的键值对对象并封装到set集合中,然后增强for遍历通过键值对对象调用getKey方法和getValue方法获取键和值;
- 方法三:通过map.entrySet返回的set集合中的迭代器进行遍历;
- 方法四:通过map中的values方法进行遍历所有的value,但不能遍历key;
22.请你讲讲Java里面的final关键字是怎么用的?
- final关键字可以修饰类、变量、方法
- 当一个类被final关键字修饰了,表明这个类不能被继承,其中的方法都会被隐式的指定为final方法,而被final修饰的方法,是不能被重写的,
- 当一个变量被final修饰了,如果是基本数据类型的变量,则值不可改变,相当于常量,如果是引用数据类型的变量,一旦初始化,其地址值就不能发生改变,也就是说不能 再让其指向另一个对象了。
23.请你谈谈关于synchronized和lock。
- synchronize是Java的关键字,当它用来修饰一个方法或者一个代码块时,能够保证线程的安全性,synchronize在发生异常时,会自动释放线程占有的锁,因此不会造成死锁现象,使用synchronize时,等待的线程会一直等待下去,不能响应中断,也不能知道线程有没有获取到锁。Java5以后引入了自旋锁、锁粗化、轻量级锁、偏向锁来优化synchronize关键字的性能
- Lock是一个接口,使用Lock时如果出现异常,没有主动通过unLock方法去释放锁,则很有可能造成死锁现象,因此使用Lock时需要再finally块中释放锁,Lock可以让等待的线程响应中断,还可以知道线程有没有成功的获取锁。
24.请介绍一下volatile关键字?
- volatile特性之一:保证变量在线程之间的可见性,Java内存模型分为主内存、线程工作内存。比如线程A从主内存中把变量读到自己的工作内存中,做了加一的操作,但是此时还没有将新的值刷新到主内存中,B线程就已经从主内存中读数据了,那么这时B线程读到的还是没修改的旧值,加了volatile关键字后,代码会生成汇编代码,从而保证了线程之间的可见性。
- volatile 特性之二:阻止编译和运行时的指令重排。从而保证编码的有序性。
25.请介绍下synchronized锁,如果用这个关键字修饰一个静态方法,锁住了什么?如果修饰成员方法,锁住了什么?
- 修饰静态方法,以及同步代码块,锁住的是类,线程想要执行对应的同步代码,需要获取类锁
- 修饰成员方法,锁住的是对象,线程想要执行相对应的同步代码,需要获取当前调用该方法的对象实例的对象锁。
26.请解释Java中的概念,什么是构造函数?什么是构造函数重载?什么是复制构造函数 ?
- 构造函数:当对象被创建的时候,构造函数会被调用,每个类都有构造函数。在程序员没有给类提供构造函数的情况下,Java编译器会为这个类创建一个默认的无参构造函数。
- java中构造函数重载和方法重载很相似,可以为一个类创建多个构造方法,每个构造函数必须有它自己唯一的参数列表。
- Java不支持向C++那样复制构造函数。
27.请你谈谈面向对象的“六原则一法则”
- 单一职责原则:一个类只做它该做的事情;
- 依赖倒转原则:面向接口编程;
- 接口隔离原则:接口要小而专,绝不能大而全;
- 合成聚合复用原则:优先使用聚合或合成关系复用代码;
- 开闭原则:软件实体应当对扩展开放,对修改关闭;
- 迪米特法则:迪米特法则又叫最少知识原则,一个对象应当对其他对象有尽可能少的了解。
28.请说明如何通过反射获取和设置对象私有字段的值?
- 可以通过类的字节码对象的getDeclaredField方法获取指定的字段对象,然后再通过字段对象的setAccessible(true)将其设置为可以访问,接下来就可以通过get/set方法来获取/设置字段的值了。
29.请说明内部类可以引用它包含类的成员吗?如果可以,有没有限制的
- 一个内部类对象可以访问创建它的外部类对象的内容,内部类如果不是static的,那么它可以访问创建它的外部类对象的所有属性;内部类如果是sattic的,即为nested class,那么它只可以访问创建它的外部类对象的所有static属性,一般普通类只有public或package的访问修饰,而内部类可以实现static,protected,private等访问修饰。当从外部类继承的时候,内部类是不会被覆盖的,它们是完全独立的实体,每个都在自己的命名空间内,如果从内部类中明确地继承,就可以覆盖原来内部类的方法。
30.请说明Java语言 如何进行异常处理的?关键字throws、throw、try、catch、finally分别代表什么意义?在try块中可以抛出异常吗?
- Java是通过面向对象的方式进行异常处理的,即每个异常都是一个对象,并提供了一个良好的异常父类Throwable,而它有两个重要的子类:Error和Exception;Error是程序无法处理的错误,和代码无关,主要是jvm的错误;Exception是程序本身可以处理的异常,包括编译时异常和运行时异常;
- 处理异常的方式有两种
- 通过try-catch-finally语句主动处理异常,在try中写执行逻辑的代码,如果出现了异常,系统会throw一个异常,然后在catch中会捕捉相对应的异常,最终都会在finally中执行完最后的程序,finally下面就不能写逻辑程序了,否则在编译时就报错了。
- 通过在方法名后面加throws 和异常对象名抛出异常,异常被动的由jvm处理,但这种方式程序会不正常的停止。
31.请判断当一个对象被当作参数传递给一个方法后,此方法可以改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递,还是引用传递?
- 是值传递。Java 编程语言只有值传递参数。当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用。对象的内容可以在被调用的方法中改变,但对象的引用是永远不会改变的。
32.请你谈谈如何通过反射创建对象?
- 方法1:通过类对象调用newInstance()方法,例如:String.class.newInstance()
- 方法2:通过类对象的getConstructor()或getDeclaredConstructor()方法获得构造器(Constructor)对象并调用其newInstance()方法创建对象,例如:String.class.getConstructor(String.class).newInstance(“Hello”);
33.请说明Comparable和Comparator接口的作用以及它们的区别。
- Java提供了只包含一个compareTo()方法的Comparable接口。这个方法可以个给两个对象排序。具体来说,它返回负数,0,正数来表明输入对象小于,等于,大于已经存在的对象。
- Java提供了包含compare()和equals()两个方法的Comparator接口。compare()方法用来给两个输入参数排序,返回负数,0,正数表明第一个参数是小于,等于,大于第二个参数。equals()方法需要一个对象作为参数,它用来决定输入参数是否和comparator相等。只有当输入参数也是一个comparator并且输入参数和当前comparator的排序结果是相同的时候,这个方法才返回true。
34.请说明final、finally、finalize的区别。
- final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。
- finally是异常处理语句结构的一部分,表示总是执行。
- finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等
35.请解释下extends和super泛型限定符。
- 类型通配符上限:<? extends 类型>
- List<? extends Number>:它表示的类型是Number或者其子类型
- 类型通配符下限:<? super 类型>
- List<? super Number>:它表示的类型是Number或者其父类型
- 特点:
- 上界的list只能get,不能add(确切地说不能add除null之外的对象,包括Object)
- 下界的list只能add子类自己类型的,以及它的子类,父类一概不能add,不能get 除非强转 ```java import java.util.ArrayList; import java.util.List;
class Fruit {} class Apple extends Fruit {} class Jonathan extends Apple {} class Orange extends Fruit {}
public class CovariantArrays {
public static void main(String[] args) {
//上界
List<? extends Fruit> flistTop = new ArrayList
//下界List<? super Apple> flistBottem = new ArrayList<Apple>();flistBottem.add(new Apple());flistBottem.add(new Jonathan());//get Apple对象会报错//Apple apple = flistBottem.get(0);
} } ```
- 上界<? extend Fruit> ,表示所有继承Fruit的子类,但是具体是哪个子类,无法确定,所以调用add的时候,要add什么类型,谁也不知道。但是get的时候,不管是什么子类,不管追溯多少辈,肯定有个父类是Fruit,所以,我都可以用最大的父类Fruit接着,也就是把所有的子类向上转型为Fruit。 下界<? super Apple>,表示Apple的所有父类,包括Fruit,一直可以追溯到老祖宗Object 。那么当我add的时候,我不能add Apple的父类,因为不能确定List里面存放的到底是哪个父类。但是我可以add Apple及其子类。因为不管我的子类是什么类型,它都可以向上转型为Apple及其所有的父类甚至转型为Object 。但是当我get的时候,Apple的父类这么多,我用什么接着呢,除了Object,其他的都接不住。 所以,归根结底可以用一句话表示,那就是编译器可以支持向上转型,但不支持向下转型。具体来讲,我可以把Apple对象赋值给Fruit的引用,但是如果把Fruit对象赋值给Apple的引用就必须得用cast。
36.讲讲什么是泛型?
- 泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。
37.ArrayList的扩容机制
- 利用无参构造创建ArrayList对象,底层默认创建一个空数组,只有添加元素时才会创建一个长度为10 的数组,当添加的元素超过了数组长度,则会创建一个长度为原来数组长度的1.5倍的数组,再把原来的数组中的元素全部拷贝到新数组中。
38.ConcurrentHashMap 和 HashTable 的区别
- ConcurrentHashMap 和 Hashtable 的区别主要体现在实现线程安全的方式上不同。
- 底层数据结构: JDK1.7的 ConcurrentHashMap 底层采用分段数组+链表实现,JDK1.8 采用的数据结构跟HashMap1.8的结构一样,数组+链表/红黑二叉树。Hashtable 和 JDK1.8 之前的HashMap 的底层数据结构类似都是采用数组+链表的形式;
- 实现线程安全的方式(重要):①在JDK1.7的时候,ConcurrentHashMap(分段锁) 对整个桶数组进行了分割分段(Segment),每一把锁只锁容器其中一部分数据,多线程访问容器里不同数据段的数据,就不会存在锁竞争,提高并发访问率。到了 JDK1.8 的时候用 Node 数组+链表+红黑树的数据结构来实现,并发控制使用 synchronized 和CAS 来操作。synchronized只锁定当前链表或红黑树的首节点,这样只要hash不冲突,就不会产生并发,效率又提升N倍。②Hashtable(同一把锁) :使用 synchronized 来保证线程安全,效率非常低下。当一个线程访问同步方法时,其他线程也访问同步方法,可能会进入阻塞或轮询状态,如使用put 添加元素,另一个线程不能使用 put 添加元素,也不能使用 get,竞争会越来越激烈效率越低。
39.如何保证线程的安全性?
- 通过合理的时间调度,避开共享数据的存取冲突 ,另外再并行任务设计上可以通过适当的策略,保证任务与任务之间不存在共享数据,保证一个客户的计算工作和数据访问只会被一个线程完成,而不是将客户的计算工作分配给多个线程去完成。
40.并发和多线程的关系和区别?
- 并发:在操作系统中,并发是指一个时间段中有几个程序处于已启动状态,且这几个程序都是在同一个处理机上运行的,但任意时刻点上只有一个程序在处理机上运行;
- 多线程:在单个程序中同时运行多个线程完成不同的工作,称为多线程;
41.请你简要说下线程的基本状态以及状态之间的关系?
- 新建(NEW):创建一个线程 对象;
- 可运行(RUNNABLE):调用线程对象的start方法,等待获取cpu的执行权;
- 运行(RUNNING):得到cpu执行权后执行代码;
- 阻塞(BLOCKED):线程因为某种原因放弃了cpu使用权,暂时停止运行,直到再次获取cpu执行权;阻塞有三种情况:
- 等待阻塞:线程执行了wait方法
- 同步阻塞:线程执行到被另一条线程占用的同步代码时
- 其他阻塞:线程执行到了sleep方法或join方法,再或者遇到io阻塞等
- 死亡(DEAD):线程执行结束,或者出异常,退出run方法,死亡状态是不可逆的;
42.线程和进程的区别
- 进程:每个正在系统上运行的程序都是一个进程,一个进程包含了多个进程;进程可能是整个程序或是部分程序的动态执行;
- 线程:线程是一zu指令的集合,或者程序的特殊段,它可以在程序里独立执行,负责在程序里执行多个任务,线程是程序中一个单一的顺序控制流程;
43.创建线程的方式有哪些?
- 自定义类继承Thread类,重写run方法,通过创建自定义类的对象调用start方法开启线程;
- 自定义类实现Runnable接口,重写run方法,将自定义类通过Thread类的有参构造方法进行传递;
- 自定义类实现Callable接口,重写call方法,有返回值。
- 使用线程池创建
44.run()方法和start()方法的区别;
- run()方法是用来创建线程的;
- start ()方法是开启线程的,使线程进入可运行状态;
45.sleep()方法和wait()方法的区别;
- sleep方法使Thread类的静态方法;执行sleep方法线程是不放弃cpu的执行权的,达到指定的休眠时间后会自动苏醒;sleep方法不释放它所占有的锁,因此容易造成死锁现象;sleep方法可以在任何地方使用;sleep方法必须捕获异常;在执行sleep方法中有可能被其他对象调用它的interrupt方法,产生interruptException异常;
- wait方法是Object类的方法;执行wait方法的线程是处于无限等待状态中的,需要通过notify方法或者notifyAll方法来唤醒;wait方法会释放它占有的锁,因此不会出现死锁现象;wait方法必须在同步控制方法或同步代码块中使用;
46.常见的线程池有哪些?
- Executors类中有以下静态方法
- newCachedThreadPool:创建一个可缓存的线程池,如果线程池长度超过处理需要,可以灵活的回收空闲线程,若无可回收,则新建线程,线程最大并发数不可控;
- newFixedThreadPool:创建一个固定大小的线程池,可控制线程最大并发数,超出的 线程在队列中等待;
- newScheduledThreadPool:创建一个定时线程池,支持定时及周期性任务执行;
- newSingleThreadExecutor:创建一个单线程化的线程池;它只会用唯一的工作线程来执行任务;保证所有任务按照指定顺序执行
47.使用线程池的优点
- 降低资源的消耗,提升系统响应速度,提高线程的可管理性
48.自定义线程池ThreadPoolExecutor的构造方法中的七个参数有哪些?
- corePoolSize:核心线程数
- maximumPoolSize:最大线程数
- keepAliveTime:空闲线程存货时间
- unit:时间单位
- threadFactory:创建线程的工厂类;
- workQueue:阻塞队列
- handler:饱和策略(拒绝策略)
