实现线程的方式到底有几种
- 实现 Runnable 接口
- 继承 Thread 类
- 线程池创建线程
- 有返回值的 Callable 创建线程
- 定时器 Timer
实现线程只有一种方式
所有都是基于 Runnable 接口或继承 Thread 类实现的,实现Runnable 接口的类也需要丢到Thread中
事实上创建线程只有一种方式,就是构造一个 Thread 类,这是创建线程的唯一方式。
实现 Runnable 接口比继承 Thread 类实现线程要好
- 实现了 Runnable 与 Thread 类的解耦,Thread 类负责线程启动和属性设置等内容,权责分明。
- 某些情况下可以提高性能,使用继承 Thread 类方式,每次执行一次任务,都需要新建一个独立的线程,使用实现 Runnable 接口的方式,就可以把任务直接传入线程池
Java 语言不支持双继承,如果我们的类一旦继承了 Thread 类,那么它后续就没有办法再继承其他的类,但是可以多实现
线程的 6 种状态
New(新创建)
- Runnable(可运行)
- Blocked(被阻塞)
- Waiting(等待)
- Timed Waiting(计时等待)
- Terminated(被终止)

线程的状态是需要按照箭头方向来走的,比如线程从 New 状态是不可以直接进入 Blocked 状态的,它需要先经历 Runnable 状态。
线程生命周期不可逆:一旦进入 Runnable 状态就不能回到 New 状态;一旦被终止就不可能再有任何状态的变化。所以一个线程只能有一次 New 和 Terminated 状态,只有处于中间状态才可以相互转换。
wait/notify/notifyAll 方法的使用注意事项
在执行 wait 方法之前,必须先持有对象的 monitor 锁,也就是通常所说的 synchronized 锁
为什么 wait/notify/notifyAll 被定义在 Object 类中,而 sleep 定义在 Thread 类中?
1.因为 Java 中每个对象都有一把称之为 monitor 监视器的锁,由于每个对象都可以上锁,这就要求在对象头中有一个用来保存锁信息的位置。这个锁是对象级别的
2.因为如果把 wait/notify/notifyAll 方法定义在 Thread 类中,会带来很大的局限性,比如一个线程可能持有多把锁,以便实现相互配合的复杂逻辑
wait/notify 和 sleep 方法的异同?
相同点
- 它们都可以让线程阻塞。
- 它们都可以响应 interrupt 中断
不同点
- wait 方法必须在 synchronized 保护的代码中使用,而 sleep 方法并没有这个要求。
- 在同步代码中执行 sleep 方法时,并不会释放 monitor 锁,但执行 wait 方法时会主动释放 monitor 锁。
- sleep 方法中会要求必须定义一个时间,时间到期后会主动恢复,而对于没有参数的 wait 方法而言,意味着永久等待,直到被中断或被唤醒才能恢复,它并不会主动恢复。
- wait/notify 是 Object 类的方法,而 sleep 是 Thread 类的方法。
有哪几种实现生产者消费者模式的方法
- BlockingQueue
- ReentrantLock 的 Condition
- wait/notify
