进程与线程
进程
线程
java线程状态
初始状态 - NEW
实现Runnable接口和继承Thread可以得到一个线程类,new一个实例出来,线程就进入了初始状态。
可运行状态 - RUNNABLE(RUNNING/READY)
RUNNING - 线程调度程序从可运行池中选择一个线程作为当前线程时线程所处的状态。这也是线程进入运行状态的唯一一种方式
READY
- 就绪状态只是说你资格运行,调度程序没有挑选到你,你就永远是就绪状态。
- 调用线程的start()方法,此线程进入就绪状态。
- 当前线程sleep()方法结束,其他线程join()结束,等待用户输入完毕,某个线程拿到对象锁,这些线程也将进入就绪状态。
- 当前线程时间片用完了,调用当前线程的yield()方法,当前线程进入就绪状态。
-
等待状态 - WAITING
处于这种状态的线程不会被分配CPU执行时间,它们要等待被显式地唤醒,否则会处于无限期等待的状态。
超时等待状态 - TIMED_WAITING:处于这种状态的线程不会被分配CPU执行时间,直到达到一定时间后它们会自动唤醒。阻塞状态 - BLOCKED
阻塞状态是线程阻塞在进入synchronized关键字修饰的方法或代码块(获取锁)时的状态。
终止状态 - TERMINATED
当线程的run()方法完成时,或者主线程的main()方法完成时,我们就认为它终止了。这个线程对象也许是活的,但是,它已经不是一个单独执行的线程。线程一旦终止了,就不能复生。
- 在一个终止的线程上调用start()方法,会抛出java.lang.IllegalThreadStateException异常。
Java 同步机制与异步机制
同步与异步
同步
异步
阻塞与非阻塞
阻塞
非阻塞
Java 锁类
锁
锁作用
锁类型
死锁
同步锁
synchronized关键字
Java关键字,JVM内置的锁机制,自动锁定解锁访问资源(代码段、方法、对象)(临界区)
互斥锁,最多只有一个线程能够访问该锁锁定资源
实现同步机制
public class Test {
public synchronized void test0(){ //锁定方法(方法返回参数前)
// code
}
public void test1(){
synchronized(this){ //锁定代码段
// code
}
}
public void test2(){
Object o = new Object();
synchronized(o){ //锁定对象
// code
}
}
public static synchronized void test3(){ //锁定静态方法
//这时候监视器上锁的对象为这个类对象,所有该类的实例访问这个方法都会进行加锁
// code
}
}
Lock类
Lock可以通过tryLock()方法非阻塞地获取锁而。如果获取了锁即立刻返回true,否则立刻返回false。这个方法还有加上定时等待的重载方法tryLock(long time, TimeUnit unit)方法,在定时期间内,如果获取了锁立刻返回true,否则在定时结束后返回false。在定时等待期间可以被中断,抛出InterruptException异常。而Synchronized在获得锁的过程中是不可被中断的。
2、Lock可以通过lockInterrupt()方法可中断的获取锁,与lock()方法不同的是等待时可以响应中断,抛出InterruptException异常。
3、Synchronized是隐式的加锁解锁,而Lock必须显示的加锁解锁,而且解锁应放到finnally中,保证一定会被解锁,而Synchronized在出现异常时也会自动解锁。但也因为这样,Lock更加灵活。
4、Synchronized是JVM层面上的设计,对对象加锁,基于对象监视器。Lock是代码实现的
可重入锁
ReentrantLock与Synchronized都是可重入锁。可重入意味着,获得获得锁的线程可递归的再次获取该锁。当所有锁释放后,其他线程才可以获取锁。
Synchronized
ReentrantLock
公平锁与非公平锁
ReentrantLock可以通过构造函数参数控制锁是否公平
读写锁
乐观锁与悲观锁
Java 线程类
volatile
多线程编程
实现多线程的三种方式
- 继承Thread类实现多线程
- 实现Runnable接口方式实现多线程
- 使用ExecutorService、Callable、Future实现有返回结果的多线程
线程池原理
多线程性能问题
确定创建多少个线程可能是一个棘手的问题,因为更多的线程并不总是会导致更快的代码:如果使用太多的线程,则代码的性能实际上可能会下降。
有几个规则可以告诉您选择多少线程。 这主要取决于您要执行的操作类型以及可用内核的数量。
计算密集型操作应使用少于或等于内核数的线程数,而IO密集型操作(如复制文件)对CPU无用,因此可以使用更多线程。异步编程
CompletableFuture
参考
https://tech.meituan.com/2020/04/02/java-pooling-pratice-in-meituan.html