线程的概念
程序 —— 数据结构 + 算法,主要指存放在硬盘上的可执行文件
进程 —— 主要指运行在内部中的程序
(目前主流的操作系统都支持多进程,是为了让操作系统可以同时执行多个任务,但进程是重量级的,新建进程对系统资源的消耗较大,因此进程的数量比较局限)
线程 —— 线程是进程内部的程序流,也就是说操作系统支持多进程,而每个进程的内部又支持多线程,并且线程是轻量级的,会共享所在进程的资源,因此以后主流的开发都采用多线程技术
多线程 —— 采用时间片轮转法来保证并发执行的效果,所谓并发就是指宏观并行微观串行的机制
线程的创建
(1)创建方式
java.lang.Thread类用于描述线程,Java虚拟机允许运行多个执行线程,而线程的创建和启动方法如下:
- 自定义类继承Thread类并重写run()方法,创建该类的对象调用start()方法
- 自定义类实现Runnable接口并重写run()方法,创建该类的对象作为实参来构造
Thread类的对象,然后使用Thread类对象调用start()方法
(2)相关的方法
- Thread()
使用无参形式构造对象 - Thread(String name)
根据参数指定的名称来构造对象 - Thread(Runnable target)
根据参数指定的引用来构造对象 - Thread(Runnable target, String name)
根据参数指定引用和名称来构造对象 - void run()
— 若使用Runnable接口构造对象后调用该方法,则最终调用Runnable引用
— 指向实现类中的run()方法,否则调用该方法则表示啥也不干 - void start()
用于启动线程,Java虚拟机会自动调用该线程的run()方法
(3)原理分析
- 执行main()方法的线程叫做主线程,执行run()方法的线程叫做子/新线程
- 对于start()方法调用代码以及之前的代码来说,由主线程执行一次,当start()方法
调用结束后,则线程的个数瞬间由1个变成了2个,其中新启动的线程去执行run()方法,
原来的主线程继续向下执行,两个线程各自独立运行 - 当run()方法结束后则子线程结束,当main()方法结束后则主线程结束,两个线程的
执行先后次序没有明确的规定,由系统调度算法来决定
(4)注意事项
继承方式创建和启动线程的代码相对简单,但Java语言中只支持单继承,若该类继承Thread类后则无法继承其它类,而实现接口的方式虽然代码复杂,但不影响该类继承其它类以及实现其它接口,因此以后的开发中推荐使用实现接口的方式
(5)线程的编号和名称
- long getId()
用于获取线程的标识符/编号 - String getName()
同于获取线程的名称 - void setName(String Name)
用于更改线程的名称 - static Thread currentThread()
用于获取当前正在执行线程的引用并返回
线程的状态和方法
(1) 线程的主要状态
- 新建状态
— 当线程对象使用new关键字创建完毕后进入的状态
— 此时线程还没有开始执行 - 就绪状态
— 当线程对象调用start()方法后进入的状态
— 此时线程依然没有开始执行 - 运行状态
— 当线程调度器调度就绪线程后进入的状态
— 此时线程开始执行
— 当时间片执行完毕后线程的任务没有完成时回到就绪状态 - 消亡状态
— 当时间执行完毕后线程的任务已经完成时进入的状态
— 此时线程已经终止 - 阻塞状态
— 当线程执行的过程中发生了阻塞事件后进入的状态,如:sleep()方法
— 当阻塞状态解除后回到就绪状态
(2)线程的常用方法
- static void sleep(long millis)
用于使得调用线程休眠参数指定的毫秒数 - int getPriority()
用于获取线程的优先级 - void setPriority(int newPriority)
— 用于设置线程的优先级
— 优先级高的线程不一定先执行,但是该线程获得CPU时间片的机会更多一些 - void join()
用于等待调用线程终止 - void join(long millis)
用于等待线程的最长时间为参数指定的毫秒数 - boolean isDaemon()
用于判断该线程是否为守护线程 - void setDaemon(boolean on)
— 用于设置该线程为守护线程
— 该方法必须在启动线程前调用
— 当所有非守护线程结束后,则守护线程会随之结束,此时Java虚拟机退出。
(若希望别的线程结束后这个线程也会随着结束,就可把这个线程标记为守护线程)