多线程
Java 给多线程编程提供了内置的支持。 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
多线程是多任务的一种特别的形式,但多线程使用了更小的资源开销。
这里定义和线程相关的另一个术语 - 进程:一个进程包括由操作系统分配的内存空间,包含一个或多个线程。一个线程不能独立的存在,它必须是进程的一部分。一个进程一直运行,直到所有的非守护线程都结束运行后才能结束。
多线程能满足程序员编写高效率的程序来达到充分利用 CPU 的目的。
进程:正在运行的一个程序,系统会为这个进程分配独立的内存资源
线程:具体执行任务的最小单位,一个进程最少拥有一个线程(主线程 运行起来就执行的线程)
- 线程之间是共享内存资源的(进程申请的)
- 线程之间可以通讯(数据传递:多数为主线程和子线程)
- 每一个线程都有自己的运行回路(生命周期)
- 线程的生命周期 状态
线程的生命周期 状态
线程是一个动态执行的过程,它也有一个从产生到死亡的过程。
- NEW:新建 线程刚被创建好 使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。
- RUNNABLE: 就绪状态 只要抢到时间片就可以运行 当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。
- RUN:如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。
- BLOCKED:如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:
1.等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。
2.同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。
3.其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。
- TERMINATED:一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。
为什么需要创建子线程 - 如果在主线程中存在比较耗时的操作:
- 这些操作会阻碍主线程,后面的任务必须等这些任务执行完毕之后才能执行,用户体验极差
- 为了不阻塞主线程,需要将耗时的任务放在子线程里去处理
如何创建一个子线程
- 写一个类继承于Thread 实现run方法
- join:让当前这个线程阻塞 等join的线程执行完毕再执行
- setName:设置线程名称
- getName:获取线程名称
- currentThread:获取当前运行的线程对象
2.实现Runnable接口 实现run方法
- a.创建任务 创建类实现Runnable接口
- b.使用Thread 为任务分配线程
- 3.开启任务 start
线程的安全
多个线程操作同一个资源,线程无法确认自己什么时候被阻塞
*synchronized Lock 加锁解锁
*synchronized 同步监听器 需要一把锁
* 任何一个对象都有一把锁
* 如果多个线程操作一个代码块并且需要同步,那么必须操作同一个对象/同一把锁
* synchronized
1.同步代码块
synchronized(监听器/对象/锁){
需要同步的代码
}
2.同步方法
必须确保多个对象调用的同步方法时操作的同一个对象
public synchronized void test()
本质就是同步代码块
等价于
synchronized (this){
test();
}
wait notify notifiall
死锁
A -> B
B -> A
Lock
ReentrainLock 可重入锁
使用接口实现线程间数据毁掉
Person
线程 Agent
线程的优先级
每一个 Java 线程都有一个优先级,这样有助于操作系统确定线程的调度顺序。
Java 线程的优先级是一个整数,其取值范围是 1 (Thread.MIN_PRIORITY ) - 10 (Thread.MAX_PRIORITY )。
默认情况下,每一个线程都会分配一个优先级 NORM_PRIORITY(5)。
具有较高优先级的线程对程序更重要,并且应该在低优先级的线程之前分配处理器资源。但是,线程优先级不能保证线程执行的顺序,而且非常依赖于平台。