多线程概述
- 多线程是指一个进程(执行中的程序)同时运行多个线程(进程中负责程序执行的执行单元),多线程可以协作完成进程工作,其目的是更好的利用 CPU 资源
并发与并行
-
并行:多核多 CPU 或多机器处理同一段处理逻辑的时候,同一时刻多个执行流共同执行
-
并发:是指通过 CPU 的调度算法,使用户感觉像是再同时处理多个任务,但同一时刻只有一个执行流占用 CPU 执行,即使多核多 CPU 的环境下还是会使用并发,以提高处理效率,主要的调度算法有:
-
分时调度:每个线程轮流获取 CPU 使用权,各个线程平均 CPU 时间片
-
抢占式调度:Java 虚拟机使用该调度模型,它会根据线程优先级,先调度优先级高的线程,若线程优先级相同则随机选取线程执行
并发与并行
线程终止的四种方式
- run() 方法执行结束后自然终止
- 使用 stop() 方法终止
- 使用 volatile 标志位(外部控制的自然死亡)
- 使用 interrupt() 方法中断运行状态和阻塞状态线程,interrupt() 方法会改变中断状态,但如果不是在阻塞状态则不会抛出异常,通过 isInterrupt 来作为中断标志推出循环
- 注意:当线程抛出一个未被捕获的异常或错误时,线程会异常终止
守护线程
- 守护线程也称为后台线程,在通过 start() 方法调用前先调用 setDeamon(true) 将线程设置为守护线程
- 守护线程会在所有前台线程死亡后由 JVM 通知死亡
- 守护线程最大的应用就是垃圾回收线程,它是一个典型的守护线程
线程状态
线程状态
-
新建状态:创建了线程 Thread 对象就进入了新建状态
-
就绪状态:调用 start() 方法就会为线程分配私有的方法栈,程序计算器资源,如果得到 CPU 资源就会从就绪状态转为运行状态
-
运行状态:就绪状态得到 CPU 资源就会转为运行状态,执行 run() 方法,当调用 yield() 时线程会让步,从运行状态转到就绪状态,但该过程可能是及其短暂的,如果当前线程拥有较高优先级,即使让步后还是会进入运行状态
-
阻塞状态:会导致阻塞状态的方法主要有:sleep()、wait()、join()、等待获取锁、等待 I/O 等情况,在这些情况被处理后就会转为就绪状态,等待调度
-
终止状态:上述所说的四种线程终止
基本线程类 Thread 与 Runnable 接口、Callable 接口
Thread
- 继承 Thread 并重写其 run() 方法,通过线程对象的 start() 方法来启动线程
public class Test {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start();
}
}
class MyThread extends Thread{
private static int num = 0;
public MyThread(){
num++;
}
@Override
public void run() {
System.out.println("主动创建的第"+num+"个线程");
}
}
-
方法描述:
-
sleep():等待一段时间,但是不释放锁,时间到后进入就绪状态等待调度
-
wait():让线程进入等待状态,同时释放当前线程所持有的锁,直到其它线程调用此对象 notify() 或 notifyAll() 方法后,当前线程会被唤醒,进入就绪状态,等待调度(注意:wait 方法只能在 synchronized 方法里使用)
-
join():把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程,比如在线程 B 中调用了线程 A 的 join() 方法,直到线程 A 执行完毕后才会继续执行线程 B
-
notify() 与 notifyAll():notify 只会通知一个在等待的对象,而 nofityAll() 会通知所有再等待的对象
Runnable
- 实现 Runnable 接口需重写 run 方法
- Runnable 是"任务",通过实现该接口,定义一个任务,然后将子任务交由 Thread 去执行
public class Test {
public static void main(String[] args) {
System.out.println("主线程ID:"+Thread.currentThread().getId());
MyRunnable runnable = new MyRunnable();
Thread thread = new Thread(runnable);
thread.start();
}
}
class MyRunnable implements Runnable{
public MyRunnable() {
}
@Override
public void run() {
System.out.println("子线程ID:"+Thread.currentThread().getId());
}
}
Thread 与 Runnable 区别
- Thread 是线程、而 Runnable 是任务,一个任务可以由多个线程去完成
- Java 不允许多继承、因此可实现 Runnable 接口在继承其它类
网友评论