1.线程和进程有什么区别?
进程:
程序由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至CPU,数据加载至内存,在指令运行过程中还需要用到磁盘,网络等设备,进程就是用来加载指令,管理内存,管理IO的.
当一个程序被运行,从磁盘加载这个程序的代码至内存,这时就开启了一个进程.
进程就可以视为程序的一个实例,大部分程序可以同时运行多个实例进程(例如记事本,画图,浏览器等),也有的程序只能启动一个实例进程(例如网易云音乐,360安全卫士等).
线程:
一个进程之内可以分为一到多个线程.
一个线程就是一个指令流,将指令流中的一条条指令以一定的顺序交给CPU执行.
2.并发和并行有什么区别?
并发(concurrent)是同一时间应对多件事件的能力:
单核cpu下,线程实际还是串行执行的,操作系统中有一个组件叫做任务调度器,将cpu的时间片(windows下时间片最小约为5毫秒)分给不同的程序使用,只是由于cpu在线程间(时间片很短)的切换非常快,人的感觉是同时运行的,总结为一句话就是:微观串行,宏观并行,一般会将这种线程轮流使用CPU的做法称为并发,concrrent.
并行(parallel)是同一时间动手做多件事情的能力:
多核cpu下,每个核(core)都可以调度运行线程,这时候线程可以是并行的,
3.线程创建的4中方式?
方法一:直接使用Thread
// 创建线程对象
Thread t = new Thread() {
public void run() {
// 要执行的任务
}
};
// 启动线程
t.start();
方法二:使用Runnable配合Thread
Runnable runnable = new Runnable() {
public void run(){
// 要执行的任务
}
};
// 创建线程对象
Thread t = new Thread( runnable );
// 启动线程
t.start();
方法三:FutureTask配合Thread
// 创建任务对象
FutureTask<Integer> task3 = new FutureTask<>(() -> {
log.debug("hello");
return 100;
});
// 参数1 是任务对象; 参数2 是线程名字,推荐
new Thread(task3, "t3").start();
// 主线程阻塞,同步等待 task 执行完毕的结果
Integer result = task3.get();
log.debug("结果是:{}", result);
方法四:线程池
4.线程有哪些状态?
站在JavaAPI的角度:
1.新建(NEW): new Thread(); 当使用new关键字创建Thread对象,此时的线程只是一个java对象并没有和操作系统真正的线程关联;
2.可运行状态(RUNABLE): 调用start方法,当调用线程对象的start,线程对象就会和操作系统真正的线程关联,可以由CPU调度执行;
3.终结状态:run方法中代码执行完毕,当线程中的代码被cup执行完毕后,线程就处于终结状态
新建->可运行->终结是不可逆的.
4.阻塞状态:没有获取线程锁的线程,线程在执行的时候,可能多个线程抢占同一把锁。没有获取锁的线程处于阻塞状态.
当获取锁的线程释放掉锁,重新抢占锁成功->可运行状态.
5.等待状态:获取锁的线程,调用锁对象.wait方法
当其他线程调用锁对象.notify方法唤醒等待状态的线程,重新获取锁成功-->可运行状态.
6.有时限的等待:
获取锁的线程,调用锁对象.wait(long)方法,当其他线程调用锁对象.notify方法唤醒等待状态的线程,
重新获取锁成功-->可运行状态.
时间到了重新获取锁成功--->可运行状态.
调用线程sleep(long)方法:
时间到了--->可运行状态,
5.为什么要使用线程池?
1.减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务.
2.可以根据系统的承受能力,调整线程池中工作线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程大概需要1MB内存,线程开的越多,消耗的内存就越大,最后死机).
6.线程池的构造方法里几个参数的作用分别都是什么?
线程池就是管理线程的一个容器;在java中线程池的实现,ThreadPoolExecutor.
ThreadPoolExecutor构造方法中的7个参数.
corePoolSize核心线程数目- 池中会保留的最多线程数;
maximumPoolSize最大线程数目 - 核心线程+急救线程的最大数目;
keepAliveTime生存时间- 救急线程的生存时间,生存时间内没有新任务,此线程资源会释放,
unit 时间单位 - 救急线程的生存时间单位(秒, 毫秒等)
workQueue -工作队列,当没有空闲核心线程时,新来的任务会加入到此队列排队,队列满会创建救急线程执行任务,当我们使用submit方法向线程池中添加一个任务;如果所有的核心线程都在执行任务;该任务就会被加入WorkQueue
threadFactory线程工厂- 可以定制线程对象的创建,例如设置线程名字,是否是守护线程等
handler拒绝策略 - 当所有线程都在繁忙,workQueue也放满时,会触发拒绝策略.
7.线程池流程
1.当我们向线程池中添加任务(注意线程池中不能添加线程,只能添加任务,线程池中的线程是由线程池自己管理的)
2.有核心线程执行任务:
如果核心线程都在执行任务,将任务加入到任务队列 , 等待核心线程执行完成任务后,从队列中获取任务执行, 如果队列已经满了, 创建急救线程.由救急线程执行任务, 救急线程执行完成任务后, 如果在keepAliveTime时间内没有任务执行,则销毁. 如果救急线程也无法创建, 触发拒绝策略.
8.线程池的拒绝策略有哪些?
抛异常java.util.concurrent.ThreadPoolExecutor.AbortPolicy
由调用者执行任务 java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy
丢弃任务 java.util.concurrent.ThreadPoolExecutor.DiscardPolicy
丢弃最早排队任务,把新加任务添加到工作队列 java.util.concurrent.ThreadPoolExecutor.DiscardOldestPolicy
9.notify()和notifyAll()有什么区别?
notify():唤醒锁对象等待区随机一个线程,
notifyAll()唤醒锁对象等待区的所有线程.
10.wait()和sleep()的区别?
相同点:wait() ,wait(long)和sleep(long)的效果都是让当前线程暂时放弃CPU的使用权,进去WATING Time_waiting的状态.
不同点:
方法归属不同:sleep(long) 时thread的静态方法,而wait() ,wait(long) 都是Object的成员方法,每个对象都有,
醒来时机不同: 执行sleep(long)和wait(long)的线程都会在等待相应毫秒后醒来, wait(long) 和wait() 还可以被notify唤醒,wait()如果不唤醒就一直等待下去,(其他线程调用锁对象notify,可以把这个锁上处于wait状态的一个线程唤醒) 它们都可以被打断唤醒,
锁特性不同:
wait方法必须基于锁对象调用,直接调用报错,而sleep没有限制.
wait方法执行后会释放锁资源,允许其他线程获得该对象锁.
sleep如果在synchronized代码块中执行,并不会释放对象锁.
标签:面试题,Thread,对象,常见,任务,线程,执行,wait From: https://www.cnblogs.com/carney/p/17139946.html