Java 中的线程

进程和线程的区别
  • 进程
    • 进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的,系统运行一个程序即是一个进程从创建,运行到消亡的过程
    • 在 Java 中,当我们启动 main 函数时其实就是启动了一个 JVM 的进程,而 main 函数所在的线程就是这个进程中的一个线程,也称主线程
  • 线程
    • 线程与进程相似,但线程是一个比进程更小的执行单位
    • 一个进程在其执行的过程中可以产生多个线程
    • 与进程不同的是同类的多个线程共享进程的堆和方法区资源,但每个线程有自己的程序计数器、虚拟机栈和本地方法栈,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程

并发和并行
  • 并发: 同一时间段,多个任务都在执行
  • 并行: 单位时间内,多个任务同时执行

线程的状态
  • 线程状态
    • new:初始状态,线程被构建,但是还没有调用 start() 方法
    • runnable:运行状态,java 线程将操作系统中的就绪和运行两种状态成为 运行中
    • blocked:阻塞状态,表示线程阻塞与锁
    • waiting:等待状态,表示线程进入等待状态,进入该状态需要其他线程做出一些特定动作(通知或中断)
    • time_waiting:超时等待状态,和 waiting 类型,可以在指定时间内返回
    • terminated:终止状态,表示线程已经执行完毕

线程的常见方法

在这里插入图片描述

  • start():启动一个线程
  • yield():线程让步,会使当前线程让出 CPU 执行时间片,与其他线程一起重新竞争 CPU 时间片,一般情况下,优先级高的线程有更大的可能性成功竞争得到 CPU 时间片,但这又不是绝对的,有的操作系统对线程优先级并不敏感
  • sleep():让前线程休眠,与 wait 方法不同的是 sleep 不会释放当前占有的锁,sleep(long) 会导致线程进入 TIMED-WATING 状态,而 wait() 方法会导致当前线程进入 WATING 状态
  • wait():调用该方法的线程进入 WAITING 状态,只有等待另外线程的通知或被中断才会返回,需要注意的是调用 wait() 方法后,会释放对象的锁,因此,wait 方法一般用在同步方法或同步代码块中
  • join():在 线程A 中调用 线程B 的 join 方法,使得 线程A 进入阻塞状态,直到 线程B 完全执行完,线程A才结束阻塞状态
  • notify():通知一个线程继续运行
  • notifyAll():All 的含义是所有的线程,而不是所有的锁,只能唤醒等待(调用 wait() 方法等待)同一个锁的所有线程,必须在当前线程拥有监视器锁的情况下执行,否则将抛出异常IllegalMonitorStateException,任何对象都可以调用,并且无法重写此方法,因为被final修饰;只能释放一把锁,只有一个线程能得到锁,其他没有得到锁的线程会继续保持在等待状态
  • interrupted():没有任何强制线程终止的方法,这个方法只是请求线程终止,而实际上线程并不一定会终止,在调用 sleep() 方法时可能会出现 InterruptedException 异常,你可能会想在异常捕获后(try-catch 语句中的 catch)请求线程终止,而更好的选择是不处理这个异常,抛给调用者处理,所以这个方法并没有实际的用途,还有 isInterrupted() 方法检查线程是否被中断
  • setPriority():设置线程的优先级,理论上来说,线程优先级高的线程更容易被执行,但也要结合具体的系统;每个线程默认的优先级和父线程(如 main 线程、普通优先级)的优先级相同,线程优先级区间为 1~10,三个静态变量:MIN_PRIORITY = 1、NORM_PRIORITY = 5、MAX_PRIORITY = 10,使用 getPriority() 方法可以查看线程的优先级
  • isAlive():检查线程是否处于活动状态,如果线程处于就绪、运行、阻塞状态,方法返回 true,如果线程处于新建和死亡状态,方法返回 false
  • LockSupport
    • park():所在的线程调用,暂停当前线程
    • unpark():另外的线程调用,恢复某个线程的运行

  • park、unpark 与 wait、notify 的区别
    • wait、notify 必须在有锁的情况下使用(需要关联 Monitor 对象),park、unpark 没有这个限制条件
    • park、unpark 配对使用能够精确的指定具体的线程的阻塞/运行,notify 只能随机唤醒一个线程
    • park、unpark 配对使用可以先 unpark,wait、notify 配合使用不能够先 notify

sleep() 方法和 wait() 方法区别和共同点
  • 两者最主要的区别在于:sleep() 方法没有释放锁,而 wait() 方法释放了锁
  • 两者都可以暂停线程的执行
  • wait() 通常被用于线程间交互/通信,sleep() 通常被用于暂停执行
  • wait() 方法被调用后,线程不会自动苏醒,需要别的线程调用同一个对象上的 notify() 或者 notifyAll() 方法,或者可以使用 wait(long timeout) 超时后线程会自动苏醒
  • sleep() 方法执行完成后,线程会自动苏醒

实现 Runnable 接口和 Callable 接口的区别
  • Runnable 自 Java 1.0 以来一直存在,但 Callable 仅在 Java 1.5 中引入,目的就是为了来处理 Runnable 不支持的用例
  • Runnable 接口不会返回结果或抛出检查异常,但是 Callable 接口可以,所以任务不需要返回结果或抛出异常推荐使用 Runnable 接口,这样代码看起来会更加简洁

执行 execute() 方法和 submit() 方法的区别
  • execute() 方法用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功与否
  • submit() 方法用于提交需要返回值的任务,线程池会返回一个 Future 类型的对象,通过这个 Future 对象可以判断任务是否执行成功,并且可以通过 Future 的 get() 方法来获取返回值,get() 方法会阻塞当前线程直到任务完成,而使用 get(long timeout,TimeUnit unit) 方法则会阻塞当前线程一段时间后立即返回,这时候有可能任务没有执行完

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tytler

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值