https://pdai.tech/md/java/thread/java-thread-x-thread-basic.html
- 线程有哪几种状态? 分别说明从一种状态到另一种状态转变有哪些方式?
- 通常线程有哪几种使用方式?
- 基础线程机制有哪些?
- 线程的中断方式有哪些?
- 线程的互斥同步方式有哪些? 如何比较和选择?
- 线程之间有哪些协作方式?
线程的状态
线程有六种状态
- 新建(NEW):创建后尚未启动。
- 可运行(Runable):可运行状态,但是可能还没有运行,在等待CPU时间片
- 阻塞(Blocking):等待获取一个排它锁,如果其线程释放了锁就会结束此状态
- 无限期等待(Waiting):等待其它线程显式地唤醒,否则不会被分配 CPU 时间片。
- 限期等待(Timed Waiting):无需等待其它线程显式地唤醒,在一定时间之后会被系统自动唤醒。
- 死亡(Terminated):可以是线程结束任务之后自己结束,或者产生了异常而结束。
阻塞和等待的区别在于,阻塞是被动的,它是在等待获取一个排它锁。而等待是主动的,通过调用 Thread.sleep() 和 Object.wait() 等方法进入。
状态转换
创建线程
实现Runable接口
- 定义一个类实现Runable接口和run方法
- 创建Runable接口实现类的对象
- 将此Runable接口实现类的对象作为传递到Thread构造器中,创建Thread的对象。
- 通过Thread对象调用start方法启动
java
public class MyRunnable implements Runnable {
public void run() {
// ...
}
}
java
public static void main(String[] args) {
MyRunnable instance = new MyRunnable();
Thread thread = new Thread(instance);
thread.start();
}
继承Thread类
- 继承Thread类并实现run方法
- 调用start启动
java
//1.继承Thread类并实现run方法
public class MyThread extends Thread {
public void run() {
// ...
}
}
//2.调用start方法启动
public static void main(String[] args) {
MyThread mt = new MyThread();
mt.start();
}
实现Callable接口
Callable 可以有返回值,返回值通过 FutureTask 进行封装。
- 创建一个类继承Callable接口,实现call方法
- 创建Callable接口实现类的对象。
- 将此Callable接口实现类的对象作为传递到FutureTask构造器中,创建FutureTask的对象。
- 将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()方法。
java
public class MyCallable implements Callable<Integer> {
public Integer call() {
return 123;
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyCallable mc = new MyCallable();
FutureTask<Integer> ft = new FutureTask<>(mc);
Thread thread = new Thread(ft);
thread.start();
System.out.println(ft.get());
}
线程安全互斥同步
回顾以下上一篇笔记中记录的保证线程安全的机制:Java多线程理论基础
- 互斥同步: synchronized 和 ReentrantLock
- 非阻塞同步: CAS, AtomicXXXX
- 无同步方案: 栈封闭,Thread Local,可重入代码
这里主要讲解Java 提供了两种锁机制来控制多个线程对共享资源的互斥访问
- JVM 实现的 synchronized(同步锁)
- JDK 实现的 ReentrantLock
synchronized
Java多线程之详解synchronized关键字 作用对象可以是代码块、方法、类 作用于代码块和方法时,获得的是对象锁,不同的线程通过同一个对象去调用加锁的代码块和方法时,线程会同步。不同的线程通过不同的对象去调用加锁的代码块和方法时,线程不会同步 作用于类时,获得的是类锁,作用于整个类上。也就是说两个线程调用同一个类的不同对象上的这种同步语句,也会进行同步。(作用于静态方法也是获得类锁)
ReentrantLock
ReentrantLock 是 java.util.concurrent(J.U.C)包中的锁。