创建线程的方式:
继承thread、实现runable接口(无返回值),实现callabled接口(有返回值)
用实现接口的方式来创建线程,就是创建了一个多线程的任务,内部还是由thread实现
new thread(new runable())
线程的生命周期:
创建,就绪,运行,阻塞,终止
状态:new,block, waiting,timed waiting, terminated
block:当进入同步方法但是没有获取到锁,直到锁被释放,重新进入runabled状态
waiting:线程调用wait(),调用notify重新进入runabled状态
timed waiting:调用wait(1000),或者sleep(1000),调用notify重新进入runabled状态
terminated:程序结束
block, waiting,timed waiting:成为阻塞状态
就绪和运行称为:runabled状态
谈谈Sleep和wait的区别:
所属类不同:sleep定义在Thread上
wait定义在object上:因为wait要在同步方法中或者同步代码块使用,此时
需要一个对象锁在实现多线程互斥的效果,可以说明java的锁是对象级别
处理方式:sleep会释放锁
wait不会释放锁
使用范围:sleep可以使用在任意范围
wait要在同步代码块,或者同步方法中使用
为什么wait必须写在同步代码块中?
避免cpu切换到别的线程,别的线程提早执行nodify,这样相当于没有wait,所以需要一个同步锁来把wait保护起来,然后再由别的线程唤醒
JDK提供的线程池有哪些?实际开发我们该怎么使用?线程池有哪些参数?
(1)线程池有SingleThreadExcutor 单一线程执行,有顺序
FixThreadExcutor 定长线程池
CahceThreadExcutor 可缓存
ScheduledEhreadExcutor 定时且定长
(2)
前两者,超出部分会在队列中等待,当请求队列长度达到最大,会堆积大量请求在队列,从而造成内存溢出OOM
后两者,会创建多个线程,达到最大,会造成OOM内存溢出
所以在实际开发中我们使用底层的ThreadPoolExcutor来创建线程,从而避免这些问题
(3)
线程池的关键参数:
初始化线程数量
等待队列长度
最大线程数量:全是CPU操作:最大线程数量就是cpu的核数
CPU操作和io操作:(单核)最大线程数就是(io时间占比/CPU时间占比)+1
(多核)最大线程数就是:CPU核数*单核的最大线程数
最大发呆时间:线程回收后闲置的时间,超过这段时间则去掉此线程,恢复至初始化线程数量
谈谈你对线程安全的理解?谈谈什么样的条件下,会出现线程不安全的问题?
线程安全就是在多线程的环境下,不进行任何的同步控制,就可以表现正确的数据
线程不安全:当多个线程使用同一个资源的时候
StringBuffer:线程安全,效率低
StringBuilder:线程不安全,效率高
但是平时在方法中我们一般使用StringBuilder,因为,每次调用一个方法,都相当于在栈内创建了
一个栈帧,每个栈帧内由于都new StringBuilder(),所以指向不同的堆内存空间,此时,对象都
在各自都有属于自己独有的资源,不存在抢占的问题,所以可以使用StringBuilder