1.什么是进程?
只有运行的程序才会出现进程。
正在运行的程序,是系统进行资源分配和调度的独立单元
每一个进程都有自己的内存空间和系统资源
2.多进程的意义?
提高Cpu的使用率?
单进程的计算机只能做一件事情
多进程的计算机可以在一个时间段做多件事情(一边听歌,一边敲代码)
是cpu在高效切换让我们觉得同时在进行。
3.什么是线程?
在一个进程中可以执行多项任务,每一个任务就可以当做是一个线程。一个进程中一般会包含多个线程。
线程是程序的执行单元,也是程序使用cpu的最基本单位。
什么是多线程?单线程?
单线程:程序只有一条执行路径
多线程:程序有多条执行路径
4.多线程的意义? 抛绣球?
程序的执行都是在抢cpu的执行权。
多个进程都在抢,其中有一个进程的执行路径比较多(线程数比较多),抢到的cpu执行权的几率是更高(提高进程的使用率)。
绣球:CPU的执行权(CPU资源)
大汉:进程,一个大汉就是一个进程,其中有一个大汉有分身术,那这个大汉抢到绣球的几率更高。
5.自己写程序实现多线程?
继承类 :Thread
重写 run 方法
创建对象
启动线程 start()
6.java程序的运行原理:
Java命令启动虚拟机,jvm启动会启动一个主线程
接着主线程去调用main.你可以把main当做一个线程。
7.获取或设置线程的名字
setName(string) 设置
getName()获取
Thread.currentThread() 获取当前正在执行的线程
8.线程调度模型(两种)
分时调度:所有线程轮流使用CPU执行权
抢占式调度:多个线程之间互相抢占,
优先级高的抢占到的几率高。
Java 使用的抢占式调度。
9.设置/获取优先级
优先级范围1-10 ,值越大,优先级越高
默认是5
setPriority(num) 设置
getPriority() 获取
10.线程方法
l start() 启动线程
l void setName (String) 设置线程名字
l String getName 获取名字
l static void sleep(long) 休眠,参数是休眠的时间
Thread类的静态方法,能够让当前线程休眠一段时间,让出cpu执行权限,休眠时间到,进入就绪状态
l static void yield() 线程礼让
n 礼让后回到就绪状态,但是有可能自己还会抢到CPU执行权,如果确保能够让出,使用sleep
l join() 线程加入
n t.join() 等待t线程执行结束后,再执行当前线程
l setDaemon(boolean) 守护线程
n 主公(主线程)死了,忠臣(守护线程)也会自杀
n 当执行的线程都是守护线程时(没有非守护线程执行),所有守护线程会结束掉
l 线程中断
n stop() 让线程停止/结束,方法已过时,不建议使用
n interrupt() 中断线程,抛出异常
l isInterrupted() 判断线程是否被中断
11.面试题:线程状态,生命周期?
12.实现多线程的第二种方式
a.自定义一个类,实现Runnable接口
b.重写run方法
c.创建自定义类的对象
d.创建Thread类的对象(
把自定义类的对象作为参数传递给Thread的构造)
e. Thread类的对象.start()
13.有了第一种为什么还要第二种方式?
a.避免java单继承带来的局限性
b.适合多个相同程序的代码去处理同一个资源的情况,
把线程程序的代码,数据有效分离。
14.火车票(电影票)售票问题
假设有电影票100张,有三个窗口在售卖。
出现问题:
重复 :cpu执行的原子性
负数 :延迟
解决?
同步机制synchronized
15.同步代码块
锁对象是任意对象
同步方法的锁对象是? This
静态同步方法的锁对象是? Class
16.什么是线程安全?
所谓的线程安全即不管多少个线程同时 执行,代码的运行结果总是与单个线程的执行结果是一致的。反之线程不安全。
线程的安全问题通常是由全局变量,静态变量造成。
线程不安全问题的解决:
l 加同步锁(互斥锁)synchronized
l 通过java的锁对象Lock,常用实现类ReentrantLock
n lock() 获得锁
n unlock() 释放锁
17.同步的弊端
效率低
死锁:两个或两个以上的线程在争夺资源的过程中,
发生的一种相互等待的现象。
中国人吃饭 :两根筷子
外国人吃饭:一个叉子,一把刀
中国人有:一根筷子,一把刀
外国人:一个叉子,一根筷子
死锁的产生原因:
线程间交叉调用
线程锁资源重叠,线程相互持有对方的锁资源
18.避免死锁
l 尽量避免同一线程同时持有多个锁。如果不可避免
尽量缩短锁的持有时间
l 只在必要的最短时间持有锁
19.线程间通信
wait() 进入阻塞状态,必须要通过notify唤醒
notify() 随机唤醒一个在wait中的线程
notifyAll() 唤醒所有在wait中的线程
20.生产者与消费者问题
产品类:产品名称,最大容量,当前数量
生产者:属性(产品)锁
当当前数量<最大容量 可以生产(最大容量-当前数量)
生产完成,唤醒消费者消费,停止生产
消费者:属性(产品)锁
如果购买数量(随机数=random*最大容量)> 当前数量
唤醒生产者,消费者等待
ELSE:直接购买
21.线程池
程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。而使用线程池可以提高性能。尤其是当程序创建很多线程的时候,要考虑使用线程池。
线程池特点:线程池中的线程可以重复使用,也就是说线程池的线程运行结束后,并不会死亡,而是再次回到线程池,等待下一个对象来使用。
Jdk5之前需要自己手动实现自己的线程池
Jdk5内置支持线程池。
线程池的分类:
l 可缓存线程池 newCachedThreadPool();
l 定长线程池 newFixedThreadPool(int);
l 定长线程池,支持定时及周期性任务
n newScheduledThreadPool(int)
n scheduleAtFixedRate(myRun,5,3, TimeUnit.SECONDS);
n scheduleAtFixedRate(任务,首次执行的延迟时间,周期执行间隔,时间单位)
要执行周期性的,调用子接口ScheduledExecutorService 的scheduleAtFixedRate方法
l 单个线程的线程池newSingleThreadExecutor()
创建线程池
ExecutorService executorService |
通过Executors类的静态方法创建 |
返回的ExecutorService 对象 |
通过ExecutorService里的方法去执行线程 有以下方法: |
void execute(Runnable command) |
22.sleep和wait区别
(1) sleep是Thread的方法。而wait是Object类的方法。
(2) 调用两个方法都会进入阻塞状态,但是sleep不释放对象锁。
而wait会释放对象锁。
(3) wait必须要在持有对象锁的情况下调用,否则会抛出异常,
而sleep没有此限制。
(4) wait方法如果不带超时时间,则需要通过notify或notifyAll进行唤醒。
如果带超时时间,时间过了会自动唤醒