一、线程和进程
程序(Program)用于C语言来表示就是两个部分:数据+算法。
进程(Process)是程序的一次执行过程,一个正在执行的程序,它在执行期间是动态,需要加载资源,需要释放资源,需要其它资源的协助。系统会给每个进程分配不同的内存区域。
线程(Thread),如果把进程更进一步的划分,可以分为多条执行流程。
如果一个进程包含了多线程,那么就表示这个进程支持多线程。
线程作为进程中最小的执行单元(调度的单位),每个线程将拥有独立的运行栈和程序计数器。
进程是正在运行中的程序,有自己独立的地址和空间
线程是进程内部单一的顺序控制流,可以共享所属进程的数据
多任务的处理环境中,线程是最小单位
线程的三种执行顺序
串行 第一个线程执行完了,才执行第二个,等到第二个执行完了,才执行第三个。(代码或者程序的执行默认就是串行的)
并行 发生在多个CPU同时执行多个任务。
并发 发生在一个CPU,采用时间片段的方式,同时执行多个任务。多个线程在同一个CPU上切换执行。
二、实现线程的方式
1、主线程:main方法所处的线程,称之为主线程,主线程是产生其他线程的线程,产生之后,和其他线程一起要争夺cpu的使用权
2、实现线程的四种方式
继承Thread类、实现Runnable接口、实现Callable接口、线程池
继承Thread类
实现Runnable接口
实现Callable接口
3、三种方式对比
继承Thread:不能再继承其他的类,run方法不能抛出异常。没有返回值
实现Runable接口:可以继承其他的类,run方法不能抛出异常。没有返回值
实现Callable接口:可以继承其他的类,call方法可以抛出异常,可以有返回值
注意: 以上三种方式创建线程对象的方式不同
4、run和start的区别:
直接调用run方法不会启动新线程,调用start方法会启动新线程
三、线程切换
1、sleep:Thread类的静态方法,休眠,当前线程会交出cpu的使用权,不参与争夺
2、yield :让步,Thread类的静态方法,当前线程交出cpu的使用权,但是当前线程会继续参与竞争
3、join:非静态方法,需要用拉入当前线程的另外一个线程对象进行调用,在当前线程运行的过程中,拉入另外一个线程,并且把另外一个线程会全部执行完,再继续执行当前线程,当前线程会交出cpu的使用权,不参与争夺
四、线程的状态
1、新建:线程对象被创建,但是还没有调用START方法(不会参与争夺CPU)
2、就绪状态:线程的start方法被调用,但是还未执行run方法,此刻线程正在参与争夺CPU.
3、运行状态:线程的run方法已经被调用,此刻线程已经争夺到cpu的使用权
4、阻塞状态:线程在运行过程中由于各种原因失去了CPU的使用权,并且也不参与竞争CPU.,阻塞状态结束后回到就绪状态(注意:不是运行状态)休眠、等待、join、IO操作等可能会引起线程进入阻塞状态。
5、死亡:如果执行完run方法,表示该线程处于死亡状态。
注意:由运行状态可以到就绪(如由让步引起)、阻塞、死亡。
阻塞结束后只能回到就绪状态。
NEW 新建状态
RUNNABLE == RUNNING 就绪和运行状态
BLOCKED 阻塞状态
WAITING
一个线程在等待另一个线程执行一个动作时在这个状态
TIMED_WAITING
一个线程在一个特定的等待时间内等待另一个线程完成一个动作会在这个状态
TERMINATED 死亡状态
1、新建
Thread t = new Thread();
2、就绪(当前线程可以执行)
Thread.start();
3、阻塞
Thread.sleep();
使用睡眠方法,放弃cpu的执行,将当前线程的任务处于阻塞状态
4、死亡状态
stop(); 直接终止线程
interrupt();线程中需要进行判断,将判断后代码块执行完毕,再终止线程
五、线程的优先级
线程优先级:默认是5,从低到高为1到10,线程优先级仅仅表示争夺到CPU的概率的大小,但并不表示是否能绝对的争夺到cpu.
六、守护线程:
使用setDaemon(boolean)方法可以将一个线程设置为守护(精灵)线程,守护线程是为了守护用户线程,当所
有的用户线程结束,守护线程也就随之结束,不管守护线程本身的任务是否完成。
七、Timer
Timer是一种定时器工具,用来在一个后台线程计划执行指定任务。它可以安排任务“执行一次”或者定期“执行多次”。
八、多线程方法
九、练习
1)
2)