1.Thread抽象类与Runable接口
都是用于创建多线程。
Runnable接口是一个函数式接口,它只包含一个run()方法,用于定义线程的执行逻辑。通过实现Runnable接口,并将其传递给Thread类的构造函数,可以创建一个新的线程。
Thread类是Java中表示线程的一个抽象类,它实现了Runnable接口,并提供了一些其他方法来控制线程的状态和行为。通过继承Thread类并重写其run()方法,可以创建一个新的线程。
public class MyRunnable implements Runnable {
public void run() {
// 线程执行的代码
}
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();
}
}
public class MyThread extends Thread {
public void run() {
// 线程执行的代码
}
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start();
}
}
2.并发与并行
线程由cpu调度执行,cpu同时处理线程(并行)的数量是有限的,cpu会轮询执行所有线程,由于cpu切换速度快,给我们的感觉像是“同时”执行,但实际上是交替执行的,这就是并发。
并行是多个线程 同时 执行。
并发是多个线程 交替 执行。
3.线程任务周期
NEW:新建状态,线程还未启动,可以通过start()方法启动。
RUNABLE:可执行状态,在新建状态 线程调用了start()方法
在阻塞状态 线程获得锁
在无限等待状态 被其他线程notify唤醒后 获得锁
在计时等待状态
时间到 获得锁
被其他线程notify唤醒后 获得锁
BLOCKED:阻塞状态,在可执行状态 未获得锁
在无线等待状态 被其他线程notify唤醒后 未获得锁
在计时等待状态
时间到 未获得锁
被其他线程notify唤醒后 未获得锁
TIMED WAITING:计时等待状态,在可执行状态,调用了wait(毫秒)和sleep(毫秒)方法
WAITING:无限等待状态,在可执行状态,调用wait()方法
TERMINATED:终止状态,在可执行状态,执行完毕或出现异常
4.线程池
没有线程池之前,每发起一次请求,就创建一个新的线程来处理,当请求量非常大的时候,创建线程、销毁线程的资源开销就会很大。所以线程池应运而生。
总结:线程池是复用线程的技术,用来减小资源开销。
在JDK5中提供了代表线程池的接口ExecutorService,使用实现类 ThreadPoolExecutor 来创建线程池。
ExecutorService pool = new ThreadPoolExecutor(
3, //核心线程数有3个
5, //最大线程数有5个。 临时线程数=最大线程数-核心线程数=5-3=2
8, //临时线程存活的时间8秒。 意思是临时线程8秒没有任务执行,就会被销毁掉。
TimeUnit.SECONDS,//时间单位(秒)
new ArrayBlockingQueue<>(4), //任务阻塞队列,没有来得及执行的任务在,任务队列中等待
Executors.defaultThreadFactory(), //用于创建线程的工厂对象
new ThreadPoolExecutor.CallerRunsPolicy() //拒绝策略
);
线程池可执行 Runable(无返回值) 和 Callable(有返回值)任务
5.工具类
hutool 的 ThreadUtil
6.锁
多线程伴随着线程安全问题,为了解决此问题,就要用到锁。
线程操作某个共享资源之前,先对资源加一层锁,保证操作期间没有其他线程访问资源,当操作完成后,再释放锁。
以java来说,大体分为 悲观锁 和 乐观锁,其他基本都是这两种锁的实现。
悲观锁:认为共享资源都是不安全的,随时会被其他线程操作、更改,在访问资源前加锁,访问完再解锁。
乐观锁:认为共享资源是安全的,通过CAS机制来确保线程安全。
6.1 悲观锁
synchronized
基于java同步器AQS的各种实现类
6.1.1 synchronzied
Java中的关键字,底层由Java虚拟机实现同步机制。通过两条监听器指令:MONITORENTER(进入) 和MONITOREXIT(退出)来实现同步效果(在class文件中可以看到指令)。
synchronized有三种使用方式
修饰静态方法:锁住的是该类,类下所有属性均被锁住。
修饰实例方法:锁住的是当前对象,其他对象不受影响。
修饰代码块:静态代码块----锁住的是整个类
实例代码块----锁住的是当前实例对象。
6.1.2 基于AQS的实现类
AQS全称(Abstract Queued Synchronizer),基于Java程序实现的一种 抽象队列同步器框架。
AQS