一、线程的生命周期
介绍:线程的生命周期就是线程从创建到线程销毁的过程。通过学习线程生命周期也可以清楚的知道线程中有哪些状态以及哪些可用方法
线程生命周期从新建到死亡共包含五种状态:新建状态、就绪状态、运行状态、阻塞状态、死亡状态。
1.新建状态:当实例化Thread对象后, 线程就处于新建状态. 这时线程并没有执行。
2.就绪状态:只要在代码中启动了线程,就会从新建状态,变为就绪状态。
3.运行状态:运行状态就是开始执行线程的功能。具体就是执行run()方法。
4.阻塞状态:阻塞状态时,线程停止执行。让出CPU资源。
5.死亡状态:死亡状态即线程执行结束。
二、状态之间的转换
1.让线程变为死亡状态 stop()和interrupt()
stop():可以停止一个线程。让线程处于死亡状态。(已弃用)
弃用原因:stop()本身就是不安全的,强制停止一个线程,可能导致破坏线程内容。导致错误的结果。同时程序还没有任务异常。
interrupt():interrupt()作为stop()的替代方法。可以实现中断线程, 并结束该线程。
(1)不能结束正在执行的线程
(2)interrupt()只能中断当前线程状态带有InterruptedException(中断)异常的线程。并会抛出这个中断异常。
(3)interrupt() 负责打断处于阻塞状态的线程。防止出现死锁或长时间wait(等待)。
总结:也就是说 interrupt() 只能中断处于阻塞状态并声明了中断异常的线程。
2.运行->阻塞->就绪 suspend()和resume()
suspend():可以挂起、暂停线程,让线程处于阻塞状态, 是一个实例方法(已过时)
resume():可以让suspend()的线程唤醒, 变成就绪状态(已过时)
弃用原因:suspend()挂起时, 不会释放锁,当一个线程持有锁,因为各种原因,不释放锁。其他线程又想拿到这个锁,但拿不到,这时这个锁就称为死锁。
package com.java.test;
/*
* 死锁实例
* */
public class Test04 {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
test();
}
});
thread.start();
thread.suspend();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
test();
}
});
}
private synchronized static void test(){
System.out.println("-=----");
}
}
3.Thread.sleep():线程休眠固定时间,并且不会释放锁。
三、线程之间的通信
1.什么是线程通信:需要多个线程配合完成一件事情, 如何让多个线程能够合理的切换就是线程通信需要考虑的问题. 重点在于配合
2.wait()和notify() | notifyAll()
wait(): 是Object中的方法。调用wait()后会让线程从运行状态变为阻塞状态。
wait()方法会让线程变为阻塞,阻塞的同时会释放锁。所以wait()必须要求被等待的线程持有锁,调用wait()后会把锁释放,其他线程竞争获取锁。当其他线程竞争获取到锁以后,如果达到某个条件后可以通过notify()唤醒,如果有多个wait的线程,系统判断唤醒其中一个。如果多个处于wait的线程可以使用notifyAll全部唤醒。唤醒后线程处于就绪状态。
注意:一个线程唤醒其他线程时,要求当前线程必须持有锁。
总结:
(1)使用wait()和notify() | notifyAll()要求必须有锁。
(2)wait()、notify()、notifyAll() 都是放入锁的代码中。
(3)wait()和notify() | notifyAll() 配合使用。
(4)wait()和notify() | notifyAll()都是通过锁调用的
package com.java.test;
/*
* wait()和notify()使用实例
* */
public class Test02 {
//库存
static int count = 0;
//生产者
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
synchronized ("锁"){
while (true){
if(count == 10){
"锁".notify();
try {
"锁".wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(count == 0){
System.out.println("库存已空,开始生产");
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("目前库存:"+(++count));
}
}
}
});
//消费者
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized ("锁") {
while (true) {
if (count == 0) {
"锁".notify();
try {
"锁".wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(count == 10){
System.out.println("库存已满,开始消费");
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("目前库存:" + (--count));
}
}
}
});
thread1.start();
thread.start();
}
}
3.join(): 把线程加入到另一个线程中。在哪个线程内调用join(),就会把对应的线程加入到当前线程中;join()后,会让当前线程挂起,变成阻塞状态,直到新加入的线程执行完成。当前线程才会继续执行。