多线程基础
进程和线程
什么是程序?
程序是包含有计算机指令和数据的文件。
什么是进程?
进程是程序的一次执行过程,是计算机分配资源的最小单位。
什么是线程?
一个进程中会包含若干个线程,每个线程都是一个独立的执行单位。
JVM进程
一个JVM进程中包含若干个线程
- main:主线程 (子线程1、2、3)
- Reference Handler:清理线程
- Finalizer:执行finalize()方法的线程
线程基本概念
- 单线程:单线程就是进程中只有一个线程。单线程在程序执行时,所走的程序路径按照连续顺序排下来,前面的必须处理好,后面的才会执行。
- 多线程:由一个以上的线程组成的程序称为多线程程序。Java中,一定是从主线程开始执行(main方法),然后在主线程的某个位置创建并启动新的线程。
线程的启动与创建
- 通过创建Thread实例,完成线程的创建。
- 线程的内部实现可以通过继承Thread类、实现Runnable接口等方式进行封装。
- 通过调用Thread实例的start()方法启动新线程。
线程的创建方式
- 创建线程的方式只有一种,创建一个Thread对象;
- 实现线程执行逻辑的方式有四种:
- 继承Thread类,重写run()方法;
- 实现Runnable接口,实现run()方法;
- 实现Callable接口,实现call()方法;
- 创建线程池,向线程池提交线程任务(Runnable或Callable);
线程的命名
生产环境中,为了排查问题方便,建议在创建线程的时候指定一个合理的线程名字
- 调用父类的setName()方法或在构造方法中给线程名字赋值;
- 如果没有为线程命名,系统会默认指定线程名,命名规则是Thread-N的形式
线程的休眠(暂停)
在线程中,可以通过调用 Thread.sleep(long millis) ,强迫当前线程按照指定毫秒值休眠。
线程的优先级
- 在线程中,通过setPriority(int n)设置线程优先级,范围是1-10,默认为 5
- 优先级高的线程被操作系统调度的优先级较高(操作系统对高优先级线程,调度更频繁)
- 注意:并不能代表,通过设置优先级来确保高优先级的线程一定会先执行
小结
- Java用Thread对象表示一个线程,通过调用start()启动一个新线程;
- 一个线程对象只能调用一次start()方法;
- 线程的执行代码写在run()方法中;
- 线程调度由操作系统决定,程序本身无法决定调度顺序;
- Thread.sleep()可以把当前线程暂停一段时间。
线程的状态
线程的状态有哪些?
- NEW:初始状态,线程被构建,但还没有调用start()方法;
- RUNNABLE:运行状态,调用start()方法后进入RUNNABLE状态,表示当前线程处于运行(就绪或运行);
- BLOCKED:阻塞状态,表示当前线程阻塞;
- WAITING:等待状态,表示线程进入等待状态,需要通过notify()或notifyAll()方法通知唤醒;
- TIME_WAITING:计时等待状态,该状态通过时间值自动唤醒;
- TERMINATED:终止状态,表示当前线程已经执行完毕;
线程的生命周期?
线程创建之后它将处于 NEW(初始状态),调用 start() 方法后,线程开始运行,线程这时候处于 READY(就绪状态)。当就绪状态的线程获得了cpu时间片后,就处于 RUNNING(已运行状态)。Java线程模型使用RUNNABLE来表示就绪和已运行两种状态;
当线程调用同步方法时,在没有获取到锁的情况下,线程将会进入到BLOCKED(阻塞状态);
当线程执行 wait()或join()方法之后,线程进入 WAITING(等待) 状态。
进入等待状态的线程需要依靠其他线程的通知,执行了notify()或notifyAll()方法后,线程将会返回到 RUNNABLE 状态;
当线程执行了sleep(long millis)方法或 wait(long millis)方法后,线程进入 TIMED_WAITING (计时等待),计时等待状态相当于在等待状态的基础上增加了超时限制。
当计时到达后,线程将会返回到 RUNNABLE 状态;
线程在执行完成后,将会进入到 TERMINATED(终止状态)。
线程的插队:join( )方法
通过join()方法实现线程的插队,调用完毕后会释放锁。
-
join()方法的实现
-
wait()方法
-
让当前线程处于等待状态
-
执行结束后,会自动notify唤醒
-
-
synchronized锁
-
线程的中断
通过interrupt()方法,改变中断状态值,并通过抛出一个InterruptedException异常,中断线程执行
线程的让出
基于操作系统的线程抢占模型,线程会通过yield( ) 实现当前线程对CPU时间的让出
守护线程(Daemon Thread)
用户线程与守护线程的区别
- 用户线程:我们平常创建的普通线程;
- 守护线程:用来服务于用户线程的线程,在JVM中,所有非守护线程都执行完毕后,无论有没有守护线程,虚拟机都会自动退出;而守护线程执行结束后,虚拟机不会自动退出。