Java多线程知识小抄集(四)——完结

Java多线程知识小抄集(四)——完结

本文主要整理博主遇到的Java多线程的相关知识点,适合速记,故命名为“小抄集”。本文没有特别重点,每一项针对一个多线程知识做一个概要性总结,也有一些会带一点例子,习题方便理解和记忆。

更多内容可以查阅:
Java多线程知识小抄集(一)
Java多线程知识小抄集(二)
Java多线程知识小抄集(三)

68. 如何避免死锁

死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,他们都将无法推进下去。这是一个严重的问题,因为死锁会让你的程序挂起无法完成任务,死锁的发生必须满足一下4个条件:

互斥条件:一个资源每次只能被一个进程使用。

请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。

不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺。

循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

避免死锁最简单的方法就是阻止循环等待条件,将系统中所有的资源设置标志位、排序,规定所有的进程申请资源必须以一定的顺序做操作来避免死锁。

69. 怎么检测一个线程是否拥有锁

java.lang.Thread中有一个方法:public static native boolean holdsLock(Object obj). 当且仅当当前线程拥有某个具体对象的锁时返回true

70. 如何查看线程快照?

jstack命令用来生成虚拟机当前的线程快照信息,线程快照就是当前虚拟机每一个线程正在执行的方法堆栈的集合。生成线程快照的目的主要是为了定位线程长时间没有响应的原因,如线程死锁、网络请求没有设置超时时间而长时间没有返回、死循环、信号量没有释放等,都有可能导致线程长时间停顿。这是如果能够dump出当前JVM的线程快照,就能够看出没有响应的线程究竟在做什么事情,从而定位问题。

语法:

稍加翻译一下:

-F 用来在输出不被响应时强制生成线程的快照
-m用来答应出包含Java和native代码的所有堆栈信息
-l 打印出锁的附加信息

可以配合jps命令找出pid

71. JAVA中的线程调度算法

抢占式。一个线程用完CPU之后,操作系统会根据现场优先级、线程饥饿情况等数据算出一个总的优先级并分配下一个时间片给某个线程执行。

72. Thread.sleep(0)有什么作用?

由于Java采用抢占式的线程调度算法,因此可能会出现某条线程尝尝获取到CPU控制权的情况,为了让某些优先级比较低的线程能获取到CPU控制权,可以使用Thread.sleep(0)手动触发一次操作系统分配时间片的操作,这也是平衡CPU控制权的一种操作。

73. CAS

全称CompareAndSwap。假设有三个操作数:内存值V,旧的预期值A,要修改的值B,当且仅当预期值A和内存值V相同时,才会将内存值修改为B并返回true,否则什么都不做并返回false。当然CAS一定要配合volatile变量,这样才能保证每次拿到的遍历是主内存中最新的那个值,否则旧的预期值A对某条线程来说,永远是一个不会变的值A,只要某次CAS操作失败,永远都不可能成功。

74. AQS

全称AbstractQueuedSynchronizer。如果说JUC(java.util.concurrent)的基础是CAS的话,那么AQS就是整个JAVA并发包的核心了,ReentrantLock, ReentrantReadWriteLock, CountDownLatch, Semaphore等都用到了它。

75.合理地配置线程池

需要针对具体情况而具体处理,不同的任务类别应采用不同规模的线程池,任务类别可划分为CPU密集型任务、IO密集型任务和混合型任务。

  • 对于CPU密集型任务:线程池中线程个数应尽量少,不应大于CPU核心数;
  • 对于IO密集型任务:由于IO操作速度远低于CPU速度,那么在运行这类任务时,CPU绝大多数时间处于空闲状态,那么线程池可以配置尽量多些的线程,以提高CPU利用率;
  • 对于混合型任务:可以拆分为CPU密集型任务和IO密集型任务,当这两类任务执行时间相差无几时,通过拆分再执行的吞吐率高于串行执行的吞吐率,但若这两类任务执行时间有数据级的差距,那么没有拆分的意义。

76. 多线程三大定律

  1. Amdahl 定律
    –Gene Amdahl 发现在计算机体系架构设计过程中,某个部件的优化对整个架构的优化和改善是有上限的。这个发现后来成为知名的Amdahl 定律。

比如:即使你有10个老婆,也不能一个月把孩子生下来。

  1. Gustafson 定律
    –Gustafson假设随着处理器个数的增加,并行与串行的计算总量也是可以增加的。Gustafson定律认为加速系数几乎跟处理器个数成正比,如果现实情况符合Gustafson定律的假设前提的话,那么软件的性能将可以随着处理个数的增加而增加。

比如:当你有10个老婆,就会要生更多的孩子。

  1. Sun-Ni 定律
    –充分利用存储空间等计算资源,尽量增大问题规模以产生更好/更精确的解。

比如:你要设法让每个老婆都在干活,别让她们闲着。

77. 进程间通信方式

  • 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
  • 有名管道 (named pipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
  • 信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
  • 消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
  • 信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
  • 共享内存( shared memory ) :共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。
  • 套接字( socket ) : 套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。

持续更新中~
博主呕心沥血整理发布,跪求一赞。

参考资料

  1. 《Java多线程编程核心技术》高洪岩著。
  2. 《Java并发编程的艺术》方腾飞 等著。
  3. 《Java并发编程实战》Brian Goetz等著。
  4. 深入JDK源码之ThreadLocal类
  5. JAVA多线程之扩展ThreadPoolExecutor
  6. Comparable与Comparator浅析
  7. JAVA多线程之UncaughtExceptionHandler——处理非正常的线程中止
  8. JAVA线程间协作:Condition
  9. JAVA线程间协作:wait.notify.notifyAll
  10. Java中的锁
  11. Java守护线程概述
  12. Java SimpleDateFormat的线程安全性问题
  13. JAVA虚拟机关闭钩子(Shutdown Hook)
  14. 40个Java多线程问题总结
  15. Java线程池分析


欢迎支持笔者的作品《深入理解Kafka: 核心设计与实践原理》和《RabbitMQ实战指南》,同时欢迎关注笔者的微信公众号:朱小厮的博客(ID: hiddenkafka)。
本文作者: 朱小厮

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×