实现线程的方式到底有几种

  1. 实现 Runnable 接口
  2. 继承 Thread 类
  3. 线程池创建线程
  4. 有返回值的 Callable 创建线程
  5. 定时器 Timer

实现线程只有一种方式
所有都是基于 Runnable 接口或继承 Thread 类实现的,实现Runnable 接口的类也需要丢到Thread中
事实上创建线程只有一种方式,就是构造一个 Thread 类,这是创建线程的唯一方式。

实现 Runnable 接口比继承 Thread 类实现线程要好

  1. 实现了 Runnable 与 Thread 类的解耦,Thread 类负责线程启动和属性设置等内容,权责分明。
  2. 某些情况下可以提高性能,使用继承 Thread 类方式,每次执行一次任务,都需要新建一个独立的线程,使用实现 Runnable 接口的方式,就可以把任务直接传入线程池
  3. Java 语言不支持双继承,如果我们的类一旦继承了 Thread 类,那么它后续就没有办法再继承其他的类,但是可以多实现

    线程的 6 种状态

  4. New(新创建)

  5. Runnable(可运行)
  6. Blocked(被阻塞)
  7. Waiting(等待)
  8. Timed Waiting(计时等待)
  9. Terminated(被终止)

CgotOV3JD82AdjsoAAENtGVGU1I263.png

线程的状态是需要按照箭头方向来走的,比如线程从 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 方法的异同?
相同点

  1. 它们都可以让线程阻塞。
  2. 它们都可以响应 interrupt 中断

不同点

  1. wait 方法必须在 synchronized 保护的代码中使用,而 sleep 方法并没有这个要求。
  2. 在同步代码中执行 sleep 方法时,并不会释放 monitor 锁,但执行 wait 方法时会主动释放 monitor 锁。
  3. sleep 方法中会要求必须定义一个时间,时间到期后会主动恢复,而对于没有参数的 wait 方法而言,意味着永久等待,直到被中断或被唤醒才能恢复,它并不会主动恢复。
  4. wait/notify 是 Object 类的方法,而 sleep 是 Thread 类的方法。

有哪几种实现生产者消费者模式的方法

  1. BlockingQueue
  2. ReentrantLock 的 Condition
  3. wait/notify