Java Thread 基础学习

线程生命周期

在这里插入图片描述
Java 规定了 虚拟机内的线程(非操作系统线程)的生命周期,参考 Thread 源码:

  • NEW(新建):仅定义了一个线程对象,还未调用它的 start() 方法。

    Thread state for a thread which has not yet started.

  • RUNNABLE(可运行):调用了线程的 start 方法,已经被 JVM 执行,但还在等待系统其它资源,如 CPU 时间片、I/O 等,根据操作系统知识可进一步将可运行状态细分为就绪、运行中两种状态(Java 并没有进一步细分)。

    Thread state for a runnable thread. A thread in the runnable state is executing in the Java virtual machine but it may be waiting for other resources from the operating system such as processor.

    • 就绪:调用了 start 方法,但没有得到 CPU 时间片的状态
    • 运行中:得到了 CPU 时间片的状态,正在执行
  • BLOCKED(阻塞):线程等待 monitor lock 的状态,只有得到了这个对象锁之后,状态才会由阻塞变为就绪

    等待 monitor lock 进入被锁住的代码块,或者在调用 wait() 方法之后又进入被锁住的代码块(A thread in the blocked state is waiting for a monitor lock to enter a synchronized block/method or reenter a synchronized block/method after calling {@link Object#wait() Object.wait}.)

    • 等待阻塞:运行的线程执行 o.wait() 方法,JVM 会把该线程放入等待队列(waitting queue)中

    • 同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则 JVM 会把该线程放入锁池(lock pool)中

    • 其他阻塞:运行的线程执行 Thread.sleep(long ms) 或t.join() 方法,或者发出了 I/O 请求时,JVM 会把该线程置为阻塞状态,当 sleep() 状态超时、join() 等待线程终止或者超时、或者 I/O 处理完毕时,线程重新转入可运行(runnable)状态

  • WAITING(等待)

    A thread in the waiting state is waiting for another thread to perform a particular action.

    • 等待另一个线程的特定操作的状态,等待被其他线程唤醒

    • 等待的过程是主动等待的,而阻塞是得不到对象锁而被动阻塞住

    • 当线程拿到锁之后,调用相应锁对象的 wait()、join()、继承 LockSupport 类的 park() ,调用其中的方法线程就会处于这个状态。

  • TIMED_WAITING(有限期等待或超时等待)

    Thread state for a waiting thread with a specified waiting time.

    • 等待另一个线程执行指定等待时间的操作的线程处于此状态
    • 等待另一个线程特定时间,时间过后会自动唤醒
    • 线程执行 sleep()、wait(long)、join(long)、LockSupport.parkNanos 、LockSupport.parkUntil 方法时会处于这种状态
  • TERMINATED(终止):线程业务逻辑执行完成退出的状态
    Thread state for a terminated thread.The thread has completed execution.

从获取 锁 的角度,阻塞分为 3 种情况

  • 等待阻塞(wait pool):调用 wait() 方法之后(释放锁)
  • 同步阻塞(lock pool):synchronized,lock.lock 操作之后,获取锁等待的状态
  • 其它阻塞(blocked):Thread.sleep(),t1.join() 执行之后(不释放锁)
    在这里插入图片描述

线程具有的方法

主要讲解它的方法以及状态的切换、锁持有状态

  • Thread.sleep(long millis),一定是当前线程调用此方法,线程进入 TIME_WAITING 状态,但不释放对象锁,millis 后线程自动苏醒进入就绪状态。

    作用:给其它线程执行机会的最佳方式。

  • Thread.yield(),一定是当前线程调用此方法,当前线程放弃获取的 cpu 时间片,由运行状态变会就绪状态,让 OS 再次选择线程。

    作用:让相同优先级的线程轮流执行,但并不保证一定会轮流执行。实际中无法保证 yield() 达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。Thread.yield() 不会导致阻塞。

  • t.join()/t.join(long millis),当前线程里调用其它线程 t 的 join 方法,当前线程进入 TIME_WAITING 状态,当前线程不释放已经持有的对象锁。线程 t 执行完毕或者 millis 时间到,当前线程进入就绪状态。

  • obj.wait(),当前线程调用对象的 wait() 方法,当前线程释放对象锁,进入等待队列。依靠 notify()/notifyAll() 唤醒或者 wait(long timeout) timeout 时间到自动唤醒。

  • obj.notify() 唤醒在此对象监视器上等待的单个线程,选择是任意性的。notifyAll() 唤醒在此对象监视器上等待的所有线程。

终止线程的 4 种方式

  • 正常结束

  • 退出标识:有些线程需要长时间的运行,只有在外部某些条件满足的情况下,才能关闭这些线程

  • Interrupt() 方法

    • 线程处于阻塞状态:调用 interrupt() 方法会抛出异常,此时要退出线程必须 catch 异常,并使用 break 方法退出。

    • 线程不处于阻塞状态:使用 isInterrupted() 判断线程的中断标志来退出循环,当使用 interrupt() 方法时,中断标志就会置 true

  • stop 方法:thread.stop() 调用之后,创建子线程的线程就会抛出 ThreadDeatherror 的错误,并且会释放子线程所持有的所有锁。一般任何进行加锁的代码块,都是为了保护数据的一致性,如果在调用 thread.stop() 后导致了该线程所持有的所有锁的突然释放(不可控制),那么被保护数据就有可能呈现不一致性

wait 和 sleep 区别

共同点:

  • 他们都是在多线程的环境下,都可以在程序的调用处阻塞指定的毫秒数,并返回。

  • wait() 和 sleep() 都可以通过 interrupt() 方法 打断线程的暂停状态 ,从而使线程立刻抛出 InterruptedException。

如果线程 A 希望立即结束线程 B,则可以对线程 B 对应的 Thread 实例调用 interrupt 方法。如果此刻线程 B 正在 wait/sleep /join,则线程 B 会立刻抛出 InterruptedException,在 catch() {} 中直接 return 即可安全地结束线程。

需要注意的是,InterruptedException 是线程自己从内部抛出的,并不是 interrupt() 方法抛出的。对某一线程调用 interrupt() 时,如果该线程正在执行普通的代码,那么该线程根本就不会抛出 InterruptedException。但是,一旦该线程进入到 wait()/sleep()/join()后,就会立刻抛出 InterruptedException 。

不同点:

  1. Thread类的方法:sleep(),yield()等 。Object的方法:wait()和notify()等
  2. 每个对象都有一个锁来控制同步访问。Synchronized关键字可以和对象的锁交互,来实现线程的同步。
    sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。
  3. wait,notify 和 notifyAll 只能在同步控制方法或者同步控制块里面使用,而 sleep 可以在任何地方使用
  4. sleep 必须捕获异常,而 wait,notify和notifyAll 不需要捕获异常

所以sleep() 和 wait() 方法的最大区别是:sleep() 睡眠时,保持对象锁,仍然占有该锁;而 wait() 睡眠时,释放对象锁。但是 wait() 和 sleep() 都可以通过 interrupt() 方法打断线程的暂停状态,从而使线程立刻抛出 InterruptedException(但不建议使用该方法)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值