Java之多线程基础
一、进程
进程指运行中的程序,占用一定的内存空间。存在自身的生命周期。
二、线程
线程由进程创建,是一个进程的实体。一个进程可以拥有多个线程。
1、单线程
同一时刻,只允许执行一个线程
2、多线程
同一时刻,可以执行多个线程。【比如:迅雷同时下载多个文件】。主线程挂了,如果还有子线程存在,整个应用程序【进程】还存活着。
3、创建线程类的两种方法
3.1、继承Thread类,重写run方法
Thread底层也是继承了Runnable接口,从而重写了Runnable接口的run方法。
Cat cat = new Cat();
cat.start(); // 调用线程类重写的run方法, 让线程变为可运行状态
3.2、实现Runnable接口,重写run方法
Java是单继承的,如果已经继承了其他类,该类可以实现Runnable接口来创建线程类。适合多个线程共享一个资源:即是多个Thread对象绑定同一个线程对象。
Cat cat = new Cat();
// 代理模式: Runnable接口是没有start方法的 可以传入Runnable类型的对象给Thread类,
// 通过动态绑定,实现 Runnable类型的对象.start()
Thread thread = new Thread(cat);
thread.start(); // 调用线程类重写的run方法, 让线程变为可运行状态
4、为什么启动线程是start(),而不是直接调用重写的run方法
如果直接在某一个线程里调用run方法,只是通过实例对象调用的线程类的普通方法run,而并没有真正的启动一个线程,此时会阻塞原本的线程,需要把run执行完毕,才会向下执行。真正实现多线程的是start方法底层的start0方法,start0方法由JVM调用。调用了start后,线程并不会立马执行,只是具备了运行状态,线程的生命周期由CPU决定,而不是start方法。
5、线程的常用方法
- setName: 设置线程名称
- getName: 返回该线程的名称
- start:使线程进入可运行状态
- setPriority: 设置线程优先级
- sleep: 在指定的毫秒数内,让正在执行的线程休眠
- interrupt: 中断线程的休眠状态
- yield:礼让调用该方法的线程。能否成功礼让,由CPU决定。未必会礼让成功。
- join:让调用该方法的线程插个队,插队的线程执行完后,在执行其他线程。一定会插队成功。
6、用户线程
也叫工作线程,当线程的任务执行完成或者通知方式结束
7、守护线程
一般是为工作线程服务的,当其他所有的用户线程结束,守护线程自动结束
7.1、常见的守护线程:
垃圾回收机制
7.2、普通线程设置成守护线程
// 需要写在start方法之前
线程实例化对象.setDaemon(true);
8、线程的七种状态
9、线程同步机制
线程同步:当有一个线程对内存进行操作时,其他线程都不能对这个内存地址操作,需要等待排队。
10、线程死锁
多个线程竞争同一把锁,从而造成死锁,导致线程进入阻塞状态。
10.1、什么时候释放锁
- 当前线程的同步方法/同步代码块执行结束
- 当前线程在同步代码块/同步方法中遇到break、return
- 当前线程在同步代码块/同步方法中出现了未处理的异常,导致异常结束
- 当前线程在同步代码块/同步方法中执行了wait方法,当前线程暂停,并释放锁
10.2、以下情况不会释放锁
- 程序调用Thread.sleep()、Thread.yield(): 暂停当前线程,不会释放锁;
- 线程执行同步任务时,其他线程调用了该线程的suspend方法是,该线程挂起,该线程不会释放锁。
三、并发
同一时刻,多个任务交替进行。单核CPU实现多任务
四、并行
同一时刻,多个任务同时进行。多核CPU可以实现并行和并发同时存在。
1、查看电脑CPU的个数 【核数】
Runtime runtime = Runtime.getRuntime();
int count = runtime.availableProcessors();