目录

  • 一,Java多线程的基本方法
    • 1,线程等待(wait)
    • 2,线程睡眠(sleep)
    • 3,线程让步(yield)
    • 4,线程中断(interrupt)
    • 5,Join 等待其他线程终止
    • 6,为什么要用 join()方法?
    • 7,线程唤醒(notify)
    • 8,其他方法:
    • 9,线程上下文切换
    • 10,进程
    • 11,上下文
    • 12,寄存器
    • 13,程序计数器
    • 14,PCB-“切换桢”
    • 15,上下文切换的活动:
    • 16,引起线程上下文切换的原因
  • 二,同步锁与死锁
    • 1,同步锁
    • 2,死锁
    • 3,线程池原理
    • 4,线程复用
    • 5, 线程池的组成
    • 6,ThreadPoolExecutor 的构造方法如下:
    • 7,拒绝策略
    • 8,Java 线程池工作过程

一,Java多线程的基本方法

线程相关的基本方法有 wait,notify,notifyAll,sleep,join,yield 等。

1,线程等待(wait)

调用该方法的线程进入 WAITING 状态,只有等待另外线程的通知或被中断才会返回,需要注意的是调用 wait()方法后,会释放对象的锁。因此,wait 方法一般用在同步方法或同步代码块中。

2,线程睡眠(sleep)

sleep 导致当前线程休眠,与 wait 方法不同的是 sleep 不会释放当前占有的锁,sleep(long)会导致线程进入 TIMED-WATING 状态,而 wait()方法会导致当前线程进入 WATING 状态

3,线程让步(yield)

yield 会使当前线程让出 CPU 执行时间片,与其他线程一起重新竞争 CPU 时间片。一般情况下,优先级高的线程有更大的可能性成功竞争得到 CPU 时间片,但这又不是绝对的,有的操作系统对线程优先级并不敏感。

4,线程中断(interrupt)

中断一个线程,其本意是给这个线程一个通知信号,会影响这个线程内部的一个中断标识位。这个线程本身并不会因此而改变状态(如阻塞,终止等)。

1)调用 interrupt()方法并不会中断一个正在运行的线程。也就是说处于 Running 状态的线程并不会因为被中断而被终止,仅仅改变了内部维护的中断标识位而已。

2)若调用 sleep()而使线程处于 TIMED-WATING 状态,这时调用 interrupt()方法,会抛出InterruptedException,从而使线程提前结束 TIMED-WATING 状态。13/04/2018 Page 74 of 283

3)许多声明抛出 InterruptedException 的方法(如 Thread.sleep(long mills 方法)),抛出异常前,都会清除中断标识位,所以抛出异常后,调用 isInterrupted()方法将会返回 false。

4)中断状态是线程固有的一个标识位,可以通过此标识位安全的终止线程。比如,你想终止一个线程 thread 的时候,可以调用 thread.interrupt()方法,在线程的 run 方法内部可以根据thread.isInterrupted()的值来优雅的终止线程。

5,Join 等待其他线程终止

join() 方法,等待其他线程终止,在当前线程中调用一个线程的 join() 方法,则当前线程转为阻塞状态,回到另一个线程结束,当前线程再由阻塞状态变为就绪状态,等待 cpu 的宠幸。

6,为什么要用 join()方法?

很多情况下,主线程生成并启动了子线程,需要用到子线程返回的结果,也就是需要主线程需要在子线程结束后再结束,这时候就要用到 join() 方法。

7,线程唤醒(notify)

Object 类中的 notify() 方法,唤醒在此对象监视器上等待的单个线程,如果所有线程都在此对象上等待,则会选择唤醒其中一个线程,选择是任意的,并在对实现做出决定时发生,线程通过调用其中一个 wait() 方法,在对象的监视器上等待,直到当前的线程放弃此对象上的锁定,才能继续执行被唤醒的线程,被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争。类似的方法还有 notifyAll() ,唤醒再次监视器上等待的所有线程。

8,其他方法:

1)sleep():强迫一个线程睡眠N毫秒。

2)isAlive(): 判断一个线程是否存活。

3)join(): 等待线程终止。

4)activeCount(): 程序中活跃的线程数。

5)enumerate(): 枚举程序中的线程。

6)currentThread(): 得到当前线程。

7)isDaemon(): 一个线程是否为守护线程。

8)setDaemon(): 设置一个线程为守护线程。(用户线程和守护线程的区别在于,是否等待主线程依赖于主线程结束而结束)

9)setName(): 为线程设置一个名称。

10)wait(): 强迫一个线程等待。

11)notify(): 通知一个线程继续运行。

12)setPriority(): 设置一个线程的优先级。

13)getPriority()::获得一个线程的优先级。

9,线程上下文切换

巧妙地利用了时间片轮转的方式, CPU 给每个任务都服务一定的时间,然后把当前任务的状态保存下来,在加载下一任务的状态后,继续服务下一任务,任务的状态保存及再加载, 这段过程就叫做上下文切换。时间片轮转的方式使多个任务在同一颗 CPU 上执行变成了可能。

10,进程

(有时候也称做任务)是指一个程序运行的实例。在 Linux 系统中,线程就是能并行运行并且与他们的父进程(创建他们的进程)共享同一地址空间(一段内存区域)和其他资源的轻量级的进程。

11,上下文

是指某一时间点 CPU 寄存器和程序计数器的内容。

12,寄存器

是 CPU 内部的数量较少但是速度很快的内存(与之对应的是 CPU 外部相对较慢的 RAM 主内存)。寄存器通过对常用值(通常是运算的中间值)的快速访问来提高计算机程序运行的速度。

13,程序计数器

是一个专用的寄存器,用于表明指令序列中 CPU 正在执行的位置,存的值为正在执行的指令的位置或者下一个将要被执行的指令的位置,具体依赖于特定的系统。

14,PCB-“切换桢”

上下文切换可以认为是内核(操作系统的核心)在 CPU 上对于进程(包括线程)进行切换,上下文切换过程中的信息是保存在进程控制块(PCB, process control block)中的。PCB 还经常被称作“切换桢”(switchframe)。信息会一直保存到 CPU 的内存中,直到他们被再次使用。

15,上下文切换的活动:

1)挂起一个进程,将这个进程在 CPU 中的状态(上下文)存储于内存中的某处。

2)在内存中检索下一个进程的上下文并将其在 CPU 的寄存器中恢复。

3)跳转到程序计数器所指向的位置(即跳转到进程被中断时的代码行),以恢复该进程在程序中。

16,引起线程上下文切换的原因

1)当前执行任务的时间片用完之后,系统 CPU 正常调度下一个任务;

2)当前执行任务碰到 IO 阻塞,调度器将此任务挂起,继续下一任务;

3)多个任务抢占锁资源,当前任务没有抢到锁资源,被调度器挂起,继续下一任务;

4)用户代码挂起当前任务,让出 CPU 时间;

5)硬件中断;

二,同步锁与死锁

1,同步锁

当多个线程同时访问同一个数据时,很容易出现问题。为了避免这种情况出现,我们要保证线程同步互斥,就是指并发执行的多个线程,在同一时间内只允许一个线程访问共享数据。 Java 中可以使用 synchronized 关键字来取得一个对象的同步锁。

2,死锁

何为死锁,就是多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。

3,线程池原理

线程池做的工作主要是控制运行的线程的数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量超出数量的线程排队等候,等其它线程执行完毕,再从队列中取出任务来执行。他的主要特点为:线程复用;控制最大并发数;管理线程。

4,线程复用

每一个 Thread 的类都有一个 start 方法。 当调用 start 启动线程时 Java 虚拟机会调用该类的 run 方法。 那么该类的 run() 方法中就是调用了 Runnable 对象的 run() 方法。 我们可以继承重写Thread 类,在其 start 方法中添加不断循环调用传递过来的 Runnable 对象。 这就是线程池的实现原理。循环方法中不断获取 Runnable 是用 Queue 实现的,在获取下一个 Runnable 之前可以是阻塞的。

5, 线程池的组成

一般的线程池主要分为以下 4 个组成部分:

1)线程池管理器:用于创建并管理线程池

2)工作线程:线程池中的线程

3)任务接口:每个任务必须实现的接口,用于工作线程调度其运行

4)任务队列:用于存放待处理的任务,提供一种缓冲机制Java 中的线程池是通过 Executor 框架实现的,该框架中用到了 Executor,Executors,ExecutorService,ThreadPoolExecutor ,Callable 和 Future、FutureTask 这几个类。

6,ThreadPoolExecutor 的构造方法如下:


1)corePoolSize:指定了线程池中的线程数量。

2)maximumPoolSize:指定了线程池中的最大线程数量。

3)keepAliveTime:当前线程池数量超过 corePoolSize 时,多余的空闲线程的存活时间,即多次时间内会被销毁。

4)unit:keepAliveTime 的单位。

5)workQueue:任务队列,被提交但尚未被执行的任务。

6)threadFactory:线程工厂,用于创建线程,一般用默认的即可。

7)handler:拒绝策略,当任务太多来不及处理,如何拒绝任务。

7,拒绝策略

线程池中的线程已经用完了,无法继续为新任务服务,同时,等待队列也已经排满了,再也塞不下新任务了。这时候我们就需要拒绝策略机制合理的处理这个问题。

JDK 内置的拒绝策略如下:

1)AbortPolicy : 直接抛出异常,阻止系统正常运行。

2)CallerRunsPolicy : 只要线程池未关闭,该策略直接在调用者线程中,运行当前被丢弃的任务。显然这样做不会真的丢弃任务,但是,任务提交线程的性能极有可能会急剧下降。

3)DiscardOldestPolicy : 丢弃最老的一个请求,也就是即将被执行的一个任务,并尝试再次提交当前任务。

4)DiscardPolicy : 该策略默默地丢弃无法处理的任务,不予任何处理。如果允许任务丢失,这是最好的一种方案。

以上内置拒绝策略均实现了 RejectedExecutionHandler 接口,若以上策略仍无法满足实际需要,完全可以自己扩展 RejectedExecutionHandler 接口。

8,Java 线程池工作过程

1)线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面有任务,线程池也不会马上执行它们。

2)当调用 execute() 方法添加一个任务时,线程池会做如下判断:

a) 如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;

b) 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列;

c) 如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要创建非核心线程立刻运行这个任务;

d) 如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池会抛出异常 RejectExecutionException。

3)当一个线程完成任务时,它会从队列中取下一个任务来执行。

4)当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运行的线程数大于 corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它最终会收缩到 corePoolSize 的大小。

学习路径决定学习效果!
有时候很多看似复杂的知识,其实并没有多复杂,只不过你找到的那份资料把知识讲复杂了。这篇文章是接着上篇一起的,看不懂的可以看看前篇,还有一篇文章才会结束这一系列的内容,后续会持续更新!

所以,找到一份好的资料也是学习过程中,非常重要的一个点。你的检索能力越强,你就会越容易找到最合适你的资料。

本文分享给需要面试刷题的朋友,也祝愿大家顺利拿到自己想要的offer,这份资料主要包含了Java基础,数据结构,jvm,多线程等等,由于篇幅有限,以下只展示小部分面试题,有需要完整版的朋友可以点一点链接跳转领取,链接:点击免费领取获取码:CSDN

膜拜!京东大牛彻底讲透Java多线程面试题,看完直怼阿里面试官,堪称吾辈楷模!相关推荐

  1. 2023史上最全Java面试题【完整版】跳槽必备,看完轻松收撕面试官

    ✨作者简介:杨 戬,博客专家.github开源作者 ✨多年工作总结:Java学习路线总结,小白逆袭Java技术总监 ✨技术交流:定期更新Java硬核干货,不定期送书活动.助你实现技术飞跃 ✨关注公众号 ...

  2. 史上最全 Java 多线程面试题及答案

    这篇文章主要是对多线程的问题进行总结的,因此罗列了40个多线程的问题. 这些多线程的问题,有些来源于各大网站.有些来源于自己的思考.可能有些问题网上有.可能有些问题对应的答案也有.也可能有些各位网友也 ...

  3. 15个顶级Java多线程面试题及回答(高级java工程师)

    Java 线程面试问题 在任何Java面试当中多线程和并发方面的问题都是必不可少的一部分.如果你想获得任何股票投资银行的前台资讯职位,那么你应该准备很多关于多线程的问题.在投资银行业务中多线程和并发是 ...

  4. 15个顶级Java多线程面试题及答案

    转载自  15个顶级Java多线程面试题及答案 在任何Java面试当中多线程和并发方面的问题都是必不可少的一部分.如果你想获得更多职位,那么你应该准备很多关于多线程的问题. 他们会问面试者很多令人混淆 ...

  5. 精选30道Java多线程面试题

    转载自 精选30道Java多线程面试题 1.线程和进程的区别 2.实现线程有哪几种方式? 3.线程有哪几种状态?它们之间如何流转的? 4.线程中的start()和run()方法有什么区别? 5.怎么终 ...

  6. 史上最全Java多线程面试题

    转载自 史上最全Java多线程面试题及答案 多线程并发编程是Java编程中重要的一块内容,也是面试重点覆盖区域.所以,学好多线程并发编程对Java程序员来来说极其重要的. 下面小编整理了60道最常见的 ...

  7. 15个Java多线程面试题

    2019独角兽企业重金招聘Python工程师标准>>> 在任何Java面试当中多线程和并发方面的问题都是必不可少的一部分.如果你想获得任何股票投资银行的前台资讯职位,那么你应该准备很 ...

  8. 面试姊妹篇4:常见的Java多线程面试题

    主要内容 本文主要记录多线程相关的操作问题,这些问题主要出现在一些面试中,当然学会了对本身的代码能力也有提升. 目录 1.交替多线程 2.发令枪问题 3.多线程顺序执行 4.关于饥饿死锁 5.线程数设 ...

  9. Java多线程面试题-可能学了个寂寞?

    文章目录 进程和线程 并发和并行 上下文切换 sleep()和wait() start()和run() synchronized关键字 volatile关键字 ThreadLocal 线程池 Runn ...

最新文章

  1. 2021-10-14 yolov5踩坑!!!经验大赏
  2. Actionscript3.0动画编程中的几种特效举例
  3. ASP.NET Core 文件系统
  4. 重庆电子工程学院计算机专业,重庆计算机电子工程职业学院2020年招生录取分数线...
  5. Atitti.java exp ast java表达式语法ast构造器
  6. 转自: http://blog.csdn.net/xiaxiaorui2003/article/details/3838631
  7. Pentium Pro架构/流水线及其优化 (3) - 指令流水线/乱序执行核/高速缓存/分支预测/指令预取
  8. LR mobile HTTP/HTML协议实战
  9. gdb学习汇编(三)
  10. 根据crash学习ARM64虚拟地址空间布局
  11. php将xml转为array,php将xml数据转化为数组(array)
  12. JAVASCRIPT 高级程序设计 第二版pdf
  13. ESXI7.0主机安装群晖DS3617xs
  14. ethtool修改网卡mac地址流程
  15. 强化学习系列(二):Multi-armed Bandits(多臂老虎机问题)
  16. Request header field xxx is not allowed by Access-Control-Allow-Headers in preflight respon
  17. 460.LFU 缓存
  18. NVIDIA、CUDA、CUDNN、PyTorch安装吐血整理!!!
  19. CSS基础————千本樱滑落的瞬间
  20. 《第一堂棒球课》:走进棒球运动

热门文章

  1. 三年级语文课外阅读赏析——心田花开
  2. 用思维导图赏析老舍话剧著作《茶馆》
  3. 《你见,或者不见我》
  4. cad修改快捷键_CAD新手攻略:修剪(TRIM)CAD命令快捷键的使用技巧
  5. 关于计算机未来理想,关于未来与梦想的作文
  6. Lost connection to MySQL server during query的几种可能分析
  7. 软件工程复习知识点汇总(2)
  8. 吉首大学校赛 K 白山茶与红玫瑰 (线段树区间操作)
  9. WiFi基础知识讲解
  10. 星级评分原理 N次重写的分析