线程
1. 创建一个线程类
- 可以正常运行
1.1 点击start方法
- start方法内有一个start0方法,而且start0方法是一个native本地方法。是通过JNI调用的系统方法,这个start0方法对应的系统创建线程的方法是pthread_create。
2. linux的线程控制原语
2.1 centos安装man手册
yum install -y man-pages
2.2 查看pthread_create函数定义
man pthread_create
- 根据man配置的信息可以得出pthread_create会创建一个线程,这个函数是linux系统的函数,可以用C或者C++直接调用,这个函数在pthread.h, 这个函数有四个参数
- pthread_t *thread:指向线程id的指针(传出参数,调用之后会传出被创建线程的id)
- const pthread_attr_t*attr:线程属性(一般传NULL,保持默认属性)
- void *(*start_routine)(void *):线程的启动后的主体函数(需要你定义一个函数,然后传函数名即可)
- void *arg:主体函数的参数(没有可以传nulll)
- start_routine类似于Thread的run方法,具体的方法实现,都在run方法里。
3. 线程本质
- Java中的线程与操作系统有什么关系?
Java中的线程是通过JNI调用操作系统pthread_create函数创建的线程,Java的线程模型与操作系统一一对应。
4. 线程模型
- java的线程(Thread)应该叫做用户线程,对应到操作系统,还有另外一种线程叫作内核线程
- 用户线程和内核线程之间存在3种对应关系
- 一对一模型(HotSpot)
即一个用户线程对应一个内核线程,内核负责每个线程的调度
优点:
(比如JVM几乎把所有对线程的操作都交给了内核)实现线程模型的容器(jvm)简单,所以我们经常听到在java中使用线程一定要慎重就是这个原因;
缺点:
对用户线程的大部分操作都会映射到内核线程上,引起用户态和内核态的频繁切换;
内核为每个线程都映射调度实体,如果系统出现大量线程,会对系统性能有影响; - 多对一线程模型
多个用户线程对应到同一个内核线程上,线程的创建、调度、同步的所有细节全部由进程的用户空间线程库来处理。
优点:
用户线程的很多操作对内核来说都是透明的,不需要用户态和内核态的频繁切换,使线程的创建、调度、同步等非常快;
缺点:
由于多个用户线程对应到同一个内核线程,如果其中一个用户线程阻塞,那么该其他用户线程也无法执行;
内核并不知道用户态有哪些线程,无法像内核线程一样实现较完整的调度、优先级等; - 多对多模型
结合了多对一模型和一对一模型的特点,将多个用户线程映射到少数但不止一个内核线程上。
5. 线程的状态
- 线程是用户态还是内核态
需要看cpu的状态,ring0(内核态),ring1,ring2,ring3(用户态)
6. 上下文切换
- 进程内部发生系统调用(只保存进程的私有信息),进程从用户态切换到内核态;
- 进程与进程之间的切换(保存进程信息,用于切换还原后程序继续执行);
- 线程与线程之间的切换
3.1 进程内部线程与线程之间的切换;
3.2 线程与外部进程里的线程之间的切换。