13.1 线程概述
# 概述
- 多线程使程序可以同时存在多个执行片段,根据不同的条件和环境同步或异步工作
- 线程与进程的实现原理类似,但服务对象不同
进程代表操作系统平台中运行的一个程序,而一个程序中将包含多个进程
# 进程
- 一个包含自身执行地址的程序
- 多任务操作系统中,把CPU时间分配给每一个程序
- CPU利用不同时间片段交替执行进程 完成伪同时进行
# 线程
- 进程内部的多任务操作 [线程]
- 进程内部的任务称为线程,线程是进程中的实体
- 线程必须拥有父进程
- 系统资源:系统不为线程单独分配资 源,线程之间共享进程的系统资源
共享内存地址空间,即访问相同变量和对象
13.2 线程创建
# 概述
- 线程也是一种对象
- 只有实现Runnable接口或继承Thread类的对象才能成为接口
# Thread 类
· 主要方法:start()、interrupt()、join()、run()
- start() 启动线程
- run() 线程的主体方法 [需覆写]
· 常用构造方法
- Thread thread = new Thread();
- Thread thread = new Thread(Runnable simple);
- Thread thread = new Thread("ThreadName");
- Thread thread = new Thread(Runnable simple, String name);
· 代码 -- 继承Thread类 【继承java.lang.Thread类】
public class SimpleThread extends Thread{
public SimpleThread(String name){
setName(name);
}
//覆写run()实现用户所需要的功能
public void run(){
int i = 0;
while(i++ < 5){
try{
System.out.println(getName() + " 执行步骤 : " + i);
Thread.sleep(1000);//休眠1秒
}catch(Exception e){
e.printStackTrace();
}
}
}
//实例化自定义的Thread类,使用start()方法启动线程
public static void main(String[] args){
SimpleThread thread1 = new SimpleThread("线程1");
SimpleThread thread2 = new SimpleThread("线程2");
thread1.start();
thread2.start();
}
}
# Runnable 接口
· 概念
- 实现该接口就可以成为线程 [Thread类 因为实现了Runnable接口 所以具有线程接口]
- Runnable 接口只有一个run()方法 必须覆写
· 代码 -- 接口实现
public class SimpleRunnable implements Runnable{
public void run(){
int i = 15;
while(i-- >= 1){
try{
System.out.println(getName() + " 执行步骤 : " + i);
Thread.sleep(1000);//休眠1秒
}catch(Exception e){
e.printStackTrace();
}
}
}
public static void mian(String[] args){
Thread thread1 = new Thread(new SimpleRunnable(), "线程1");
thread1.start();
}
}
13.3 线程的生命周期
# 线程状态:创建、可执行、非可执行、消亡
# 创建
- 实例化一个thread对象 并执行start()方法之后,线程进入 “可执行”状态,开始执行
- 同一时间点只有一个线程在执行,转换速度快,看起来像同时执行一样
# 可执行
- 线程启动start()方法以后,进入可执行状态,执行用户覆写的run()方法
- 线程进入“可执行”状态,说明加入此应用执行安排的队列中,并不是一直执行到run()结束
- 何时给与线程执行权,由Java虚拟机和线程的优先级决定
- 可执行状态:执行完毕 或者 在等待执行权队列中
# 非可执行
- 使线程离开可执行状态下的等待队列时,进入“非可执行”状态
- 使用 Thread类中的 wait()、slepp()方法进入“非可执行”状态
- “非可执行”状态,CPU不分配时间片给这个线程
- 回到“可执行状态”:notify() interrupt()
# 消亡
- run()方法执行完毕,线程自动消亡
13.4 线程的优先级
# 优先级范围:1~10 [默认值为5]
- 可以使用Thread类的setPriority()方法来设定[设定值必为1~10]
# 执行原则:优先级高的线程被优先执行,执行完毕以后才是优先级低的线程执行
优先权相同,轮流执行
# Time slicing
- 支持:系统为每个线程分配一小段CPU时间,时间一到换到下一线程 [大部分操作系统系统]
- 不支持:每个系统执行完毕以后,才执行下一线程
礼让线程 Thread类 yield()方法
13.5 线程的控制
# 控制方式:启动、挂起、状态检查、正确结束线程 【合理安排线程执行顺序】
# 启动
- 调用线程start()方法,start()方法告诉系统该线程准备就绪,可以启动run()方法之后返回
接着继续执行start()方法下面的语句,此时run()方法可能还在继续。
# 挂起
· 概念:是线程进入“非可执行”状态,此状态下,CPU不分配时间段
在线程挂起后,可以通过重新唤醒线程使之恢复运行
· 挂起方法
- 调用sleep()方法,使线程进入休眠状态,规定休眠时间
- 调用join()方法,在线程A调用线程B的join()方法,那么线程A被挂起,直到线程B执行完毕
- 调用wait()方法,使线程挂起,直到线程得到了notify()和notifyAll()消息,进入可执行状态//通信
- 线程等待某个输入/输出完成
- suspend() resume()方法,强制挂起
# 检查状态
- isAlive()方法:测试线程是否处于活动状态,若线程已经启动且尚未终止,则为活动状态
# 结束线程
· 结束情况
- 自然消亡:一个线程从run()方法的结尾处返回,自然消亡且不能在被运行
- 强制死亡:调用Thread类中的stop()方法强制停止 //该方法已被舍弃
# 后台线程 [Deamon线程]
- 使用Thread类中的setDeamon()方法来设置一个线程为后台线程
- 必须在线程启动之前调用setDeamon()方法
- 所有非后台线程结束,那么后台线程也会终止
- 语法格式:thread.setDeamon(boolean on) // on 为true 则标记为后台线程
- 判断是否为后台线程:thread.isDeamon()
13.6 线程的同步
# 概述
- 为避免多线程共享资源时发生冲突,在线程使用资源时给该资源上锁 [同步机制]
- 共享资源:文件、输入/输出端口、打印机
- 同步形式:同步方法、同步代码块 [synchronized关键字]
# 同步方法
- 将访问资源的方法标记为synchronized,
在调用这个方法的线程执行完之前,其他调用该方法的线程被阻塞
- 声明
synchronized void sum(){...}
# 同步代码块
- 语法格式
synchronized (someobject){...}
# 产生死锁四条件 [必须同时满足]
- 互斥条件:资源不共享
- 请求与保持条件:线程等待资源
- 非剥夺条件:资源不可被强制剥夺
- 循环等待条件:A线程等待B,B线程等待A