多线程
1. 程序、进程、线程
- 程序: 是计算机指令集合必须依靠操作系统才能存在,文件存储在电脑硬盘上。
- 进程: 程序运行之后,系统会划分一块空间,每执行一次活动就产生了一个进程。
- 线程: 线程是程序的最小单位,CPU通过线程来执行进程。
- 分类:
- 分时调度: 平均分配CPU的资源,每个线程执行时间是平均的
- 抢占式调度: 根据每条线程的优先级不同执行的占用的资源也不同,同级线程是
随
机
执
行
\color{#ff0036}{随机执行}
随机执行
- 三者的关系 : 一个程序有一个或多个进程,每个进程有多个线程。
并发和并行
- 并发: 多条线程在同一时间段内交替执行
- 并行: 多条线程在同一时刻共同执行
多线程
- 优点:
- 开启线程的方式:
- 声明是Thread类的子类
public void MyThread extends Thread(){}
; - 实现Runnable接口
public void MyRunnable implements Runnable(){}
- 生命周期:
- 新线程(new): 使用new创建出一个线程对象
- 就绪状态(runnable): 线程对象调用start()方法,将状态转成就绪状态,JVM会为线程划分一个独立的栈空间,并等待CPU去执行
- 运行状态(Running): CPU执行线程
- 等待/阻塞: 线程运行时被剥夺资源或者,等待某些事件进入等待或阻塞状态(执行suspend()暂停、sleep()睡眠、wait()等待、yield()暂停等方法)。这时将会释放所有资源,但是不释放锁,所以容易引发死锁。等待事件结束后进入就绪状态
- 死亡状态: 当线程运行结束/异常出错/调用Stop方法就会停止运行,由JVM收回占用的资源。
Thread类&Runnable接口
- Thread类: 对于Java而言,每个线程都是一个独立的java.lang.Thread对象,每个线程里执行线程类中被重写的run方法内部的代码
- 构造函数:
new Thread();
new Thread(String name);
new Thread(Runnable target);
new Thread(Runnable target,String name);
- Runnable接口: 通过实现Runnable接口,并重写run方法。在创建Thread时作为一个参数传入
- 常用方法:
- start方法: 使该线程开始执行,JVM调用该线程的run 方法。多次启动(Start)一个线程是非法的
- currentThread方法: 返回当前正在执行对象的引用
Thread.currentThread()
- join方法: 底层用的是wait()方法实现的,所以只是阻止,具体谁先执行还是看start()的位置
返回值 | 语法 | 用处 |
---|
boolean | isAlive() | 测试线程是否处于活动状态 |
boolean | isDaemon() | 该线程是否是线程守护 |
boolean | isInterrupted() | 该线程是否被终断 |
void | join() | 等待该线程终止再向下运行 |
static void | sleep(long mills) | 指定线程休眠一段时间 |
void | sleep(long millis) | 暂停该线程millis毫秒 |
void | start() | 使该线程执行执行线程对象中的run方法 |
void | run() | 如果该线程是使用独立的Runnable运行对家构造的,则调用该对象的run方法,否则不执行 |
long | getId() | 返回该线程的标识符 |
void | setName(String name) | 给这个线程设置名称 |
String | getName() | 获取这个线程名称 |
Thread.State | getState() | 返回该线程的状态 |
void | interrupt() | 中断线程 |
join yield sleep wait的区别
- wait 释放锁的同时也释放了CPU的资源,线程也进入了阻塞状态
- sleep 方法不会释放锁,但释放了CPU的资源,也进入了阻塞状态
- yield方法从running状态到runnable就绪状态,让同优先级的线程获取CPU
- join方法将并发执行变成同步执行。父线程等子线程执行完成,调用join的线程会先执行完成
Synchronized 同步锁
- Synchronized它可以把任意一个非Null的对象当作锁,他属于独占式的悲观锁(它认为线程操作对象是写多读少),同时属于可重入锁。
- 作用范围
- 作用于方法,锁住的是对象的实例(this)
- 作用于静态方法时,锁住的是Class实例,又因为Class的相关数据存储在常量池中,所以相当于一个全局锁,会锁所有调用该方法的线程
- Synchronized 作用于一个对象实例时,锁住的是所有以该对象为锁的代码块。它有多个队列,当多个线程一起访问某个对象监视器的时候,对象会将这些线程存储在不同的容器中。