一、什么是进程、线程?
进程:操作系统进行资源分配的最小单元
线程:操作系统调度CPU的最小单元,线程都拥有各自的计数器、栈和局部变量等属性,并且还可以访问共享的内存变量。
关系:一个进程可以创建多个线程
二、CPU核心数和线程数的关系?
假设内核2,逻辑处理器4
能并行执行线程数,主要取决于逻辑处理器,4个逻辑处理器可以并行处理4个线程。
但是可以并发处理几千个线程都没问题(底层是时间片轮转机制 RR 时间片快速切换,每个线程拥有时间片就可以获得执行权)
三、在底层线程数据
CPU有10亿寄存器,还有cache等存储数据
当CPU执行处理线程时,线程需要用的数据都会保存在寄存器或者cache中,当时间片用完轮转后,就会把该线程的数据保存到内存等地方
当时间片再次轮转到此线程时,会从内存把数据拿到寄存器或者cache中,处理线程,不断循环直到线程被摧毁,数据被回收
四、介绍多线程的需注意api
Thread.run() | 分到CPU后才可以执行此方法,业务逻辑实现的地方 |
Thread.start() | 启动线程,让线程处于就绪状态,随时等待分配CPU |
Thread.join() | t1.join(),t1线程插队,直到t1执行完才执行其他线程 |
Thread.join(long millis) | t1.join(10),t1线程插队10毫秒,到了时间后线程交替执行 |
Thread.sleep(long millis) | 让线程进入睡眠状态,不释放锁资源,让出CPU,也属于阻塞 |
Thread.yield() | 使当前线程让出CPU,时间不可以指定,不释放锁资源 |
Thread.setDaemon(boolean on) | setEDaemon(true)当传入true就是设置为守护线程,GC就是守护线程 |
Thread.interrupt() | 中断线程,但是并不是停止线程运行,只是一个中断状态号设置成true而已,可以作后续处理 |
Thread.interrupted() | 测试 当前线程 是否已经是中断状态,执行后具有清除状态功能。内部实现是调用的当前线程的isInterrupted(),中断返回true否则false |
Thread.isInterrupted() | 测试线程 Thread 对象 是否已经是中断状态,但不清除状态标志 |
Thread.stop() | 线程停止线程,通过抛出异常的形式释放锁,会导致数据不安全,已经被淘汰(尽量用Thread.interrupt等) |
Thread.suspend() | 线程停止线程,会导致死锁问题,已经被淘汰(尽量用Thread.interrupt等) |
Object.wait() | 使线程等待,释放锁,让出CPU,阻塞,需要synchronized中才可以使用,否则会抛异常 |
Object.notify() | 唤醒正在此对象监视器上等待的单个线程 |
Object.notifyAll() | 唤醒正在此对象监视器上等待的所有线程 |
LockSupport.park() | 阻塞线程,底层是Unsafe,由os操作的,Lock锁常用 |
LockSupport.unpark() | 唤醒线程,底层是Unsafe,由os操作,Lock锁常用 |
五、线程状态
六、线程类型
用户级线程(ULT)、内核级线程(KLT)
JVM用的是内核级线程
用户线程(ULT):指不需要内核支持而在用户程序中实现的线程,其不依赖于操作系统核心,应用进程利用线程库提供创建、同步、调度和管理线程的函数来控制用户线程。另外,用户线程是由应用进程利用线程库创建和管理,不依赖于操作系统核心。不需要用户态/核心态切换,速度快。操作系统内核不知道是由应用进程利用线程库创建和管理,阻塞将使得整个进程(包括他的所有线程)阻塞
内核线程(KLT):线程的所有管理操作都是由操作系统内核完成的。内核保存的状态和上下文信息,当一个线程执行了引起阻塞的系统调用时,内核可以调度该进程的其它线程执行。在多处理器系统上,内核可以分派属于同一进程的多个线程在多个处理器上运行,提高进程执行的并行度。由于需要内核完成线程的创建、调度和管理,所以和用户级线程相比这些操作要慢得很多,但是仍然比进程的创建和管理操作要快。
测试代码如下(1000个线程运行,都休眠10s,这样在任务管理器中就可以查看到线程数会增多1000个,说明它在操作系统中也建立了线程)
for (int i = 0; i < 1000; i++) {
new Thread() {
@Override
public void run() {
try {
sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}